Complete Guide to Address Verification APIs in 2025
Everything you need to know about address verification APIs - from basic concepts to advanced implementation strategies with code examples.
Table of Contents
- What is Address Verification?
- Why Address Verification Matters
- How Address Verification Works
- Choosing the Right API
- Implementation Guide
- Step 1: Obtain Authentication Token
- Step 2: Verify Addresses
- Best Practices
- Common Pitfalls to Avoid
- Conclusion
- Frequently Asked Questions
Let's face it—incorrect addresses cost businesses millions of dollars every year. From failed deliveries and returned packages to frustrated customers and damaged brand reputation, the impact of bad address data ripples through your entire operation.
Address verification APIs solve this problem by validating, standardizing, and enriching address data in real-time. Whether you're building an e-commerce checkout, a logistics platform, or a CRM system, integrating address verification is one of the smartest investments you can make.
In this comprehensive guide, we'll walk you through everything you need to know about address verification APIs—from the fundamentals to advanced implementation strategies with real code examples.
1. What is Address Verification?
Address verification (also called address validation) is the process of checking whether a given address exists and is deliverable. It involves comparing an address against authoritative databases maintained by postal services and other data providers.
A typical address verification process involves three key steps:
- Parsing: Breaking down the address into components (street number, street name, city, state, ZIP code)
- Validation: Checking if the address exists in authoritative databases
- Standardization: Formatting the address according to postal service standards (e.g., USPS for US addresses)
Real-World Examples: See It In Action
Address verification APIs can handle various types of input errors and incomplete data. Here are actual examples from Sthan.io demonstrating its powerful capabilities:
Correcting Misspelled Street Names & Cities
1345 avvenue of americas new york ny
6000 j street sacrmento ca
325 w broaddwey # m ny 10013
3808 avenue faradiya davis ca
Filling in Missing State & ZIP Codes
543 sanders road cross
1199 w shaw avenue fresno
Handling Abbreviated & Expanded Forms
The API intelligently handles both abbreviated and expanded forms of street types, directions, and states:
1199 west shaw avenue fresno california
6000 j st sacramento ca
Restructuring Out-of-Order Addresses
1345 americas avenue NY
10094 delware bay raod derdenelle
- Corrects misspellings in street names, city names, and more
- Adds missing ZIP codes (including ZIP+4 for precision)
- Infers missing state information from context
- Handles both abbreviated (St, Ave, W, CA) and expanded (Street, Avenue, West, California) forms
- Restructures out-of-order address components
- Standardizes formatting to USPS specifications
2. Why Address Verification Matters for Your Business
The business case for address verification is compelling. Here's what you stand to gain:
💰 Reduced Shipping Costs
Failed deliveries are expensive. Between returned packages, re-shipping costs, and customer service overhead, a single failed delivery can cost $10-$30. For businesses shipping thousands of orders per month, this adds up quickly.
📈 Improved Conversion Rates
Address autocomplete and validation reduce form friction during checkout. Studies show that optimized address entry can increase conversion rates by 15-25% and reduce cart abandonment significantly.
🎯 Better Data Quality
Clean, standardized address data improves your entire operation: more accurate analytics, better customer segmentation, reliable route optimization, and effective direct mail campaigns.
😊 Enhanced Customer Experience
When customers receive their orders on time at the correct address, they're more likely to become repeat buyers and recommend your business to others.
Real-World Example: E-commerce Success
A mid-sized e-commerce company processing 50,000 orders per month implemented address verification and saw:
- Failed deliveries reduced from 3.5% to 0.4%
- Annual shipping cost savings of $186,000
- Checkout conversion rate improved by 18%
- Customer satisfaction scores increased by 22 points
3. How Address Verification Works Behind the Scenes
Modern address verification APIs use sophisticated multi-layered approaches to ensure accuracy. Here's what happens when you submit an address to Sthan.io:
Step 1: Intelligent Address Parsing
The API first normalizes and parses your input address:
Input Address
123 main st apt 4b new york ny 10001
Parsed Components
Street Number: 123Street Name: Main St
Unit: Apt 4B
City: New York
State: NY
ZIP: 10001
Key Features:
- Unit Detection: Automatically identifies unit types (Apt, Suite, Unit, #) and numbers
- Normalization: Removes commas, standardizes hyphens, and converts to lowercase for consistent matching
- Smart Parsing: Handles various address formats and abbreviations
Step 2: Multi-Source Verification Strategy
Sthan.io uses a sophisticated parallel verification approach with multiple data sources:
Verification Flow (Executed in Parallel)
- Exact Match Lookup: Searches proprietary database (160M+ addresses) using high-performance open-source search engine for instant exact matches
- Census GeoCoding API: Validates against official U.S. Census Bureau data for geocoding and address components
- USPS Verification: Cross-references with official USPS data for postal accuracy and deliverability
- Intelligent Fuzzy Matching: Uses Levenshtein distance algorithm to match misspellings and variations (as fallback)
Step 3: Advanced Fuzzy Matching (When Needed)
If exact matching fails, the API employs advanced algorithms:
- Levenshtein Distance: Calculates edit distance to find closest matches to misspelled addresses
- Word Permutations: Generates permutations of address words to handle word-order variations
- Correctness Scoring: Ranks matches by percentage of correctness (based on character similarity)
- Occurrence Analysis: When multiple matches have equal distance, selects the most frequently occurring address
Step 4: Standardization & Enrichment
The verified address is standardized and enriched with additional metadata:
USPS Standardization
- Proper abbreviations (Street → ST, Avenue → AVE)
- Capitalization per USPS standards
- ZIP+4 code for delivery point precision
- Carrier route information
Additional Enrichment
- County name
- Full address hash for de-duplication
- USPS verification flag
- Algorithm used (for transparency)
Performance & Rate Limiting
To ensure optimal performance and fair usage:
- Batch Processing: Verify up to 10 addresses per request with automatic parallel processing
- Concurrency Control: Intelligent throttling prevents overload (max 10 concurrent operations)
- Timeout Protection: 120-second timeout ensures requests don't hang indefinitely
- Rate Limiting: Per-user rate limits ensure fair access for all customers
4. Choosing the Right Address Verification API
Not all address verification APIs are created equal. Here's what to consider when evaluating providers:
Key Selection Criteria
| Criteria | What to Look For |
|---|---|
| Data Coverage | Does it cover your target countries? How frequently is data updated? |
| Accuracy | CASS certification for US addresses; validation accuracy rate 95%+ |
| Performance | API response time under 100ms; high availability SLA (99.9%+) |
| Pricing | Cost per lookup; volume discounts; free tier availability |
| Features | Autocomplete, parsing, geocoding, international support |
| Developer Experience | Clear documentation, SDKs, code samples, support quality |
5. Implementation Guide with Code Examples
Let's get practical. Here's how to integrate address verification into your application using popular programming languages.
Getting Started
First, sign up for a free account at Sthan.io. You'll receive a profile name and password that you'll use to obtain authentication tokens.
Step 1: Obtain Authentication Token
Before making any API calls, you need to authenticate and obtain a bearer token. This token will be used for all subsequent API requests.
Get authentication token using fetch API:
async function getAuthToken(profileName, profilePassword) {
const response = await fetch('https://api.sthan.io/auth/token', {
method: 'GET',
headers: {
'profileName': profileName,
'profilePassword': profilePassword
}
});
if (!response.ok) {
throw new Error(`Authentication failed: ${response.status}`);
}
const data = await response.json();
return data.Result.access_token; // Extract token from response
}
// Example usage
const token = await getAuthToken('your-profile-name', 'your-profile-password');
console.log('Authentication token:', token);
// Store token for later use
localStorage.setItem('sthan_auth_token', token); // Browser
// or
process.env.STHAN_TOKEN = token; // Node.js
Get authentication token using requests library:
import requests
import os
def get_auth_token(profile_name, profile_password):
"""
Obtain authentication token from Sthan.io API
Args:
profile_name (str): Your profile name
profile_password (str): Your profile password
Returns:
str: Authentication token
"""
url = 'https://api.sthan.io/auth/token'
headers = {
'profileName': profile_name,
'profilePassword': profile_password
}
response = requests.get(url, headers=headers)
response.raise_for_status()
data = response.json()
return data['Result']['access_token']
# Example usage
profile_name = os.getenv('STHAN_PROFILE_NAME', 'your-profile-name')
profile_password = os.getenv('STHAN_PROFILE_PASSWORD', 'your-profile-password')
token = get_auth_token(profile_name, profile_password)
print(f'Authentication token: {token}')
# Store token as environment variable for later use
os.environ['STHAN_AUTH_TOKEN'] = token
Get authentication token using Spring RestTemplate:
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import com.fasterxml.jackson.databind.JsonNode;
public class SthanAuthService {
private final RestTemplate restTemplate;
private static final String AUTH_URL = "https://api.sthan.io/auth/token";
public SthanAuthService() {
this.restTemplate = new RestTemplate();
}
public String getAuthToken(String profileName, String profilePassword) {
HttpHeaders headers = new HttpHeaders();
headers.set("profileName", profileName);
headers.set("profilePassword", profilePassword);
HttpEntity<Void> request = new HttpEntity<>(headers);
ResponseEntity<JsonNode> response =
restTemplate.exchange(AUTH_URL, HttpMethod.GET, request, JsonNode.class);
if (response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
JsonNode resultNode = response.getBody().get("Result");
return resultNode.get("access_token").asText();
}
throw new RuntimeException("Authentication failed");
}
}
// Example usage
SthanAuthService authService = new SthanAuthService();
String token = authService.getAuthToken("your-profile-name", "your-profile-password");
System.out.println("Authentication token: " + token);
// Store token in configuration or cache for reuse
Get authentication token using Go's net/http:
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type AuthResponse struct {
ID string `json:"Id"`
Result AuthResult `json:"Result"`
StatusCode int `json:"StatusCode"`
IsError bool `json:"IsError"`
}
type AuthResult struct {
AccessToken string `json:"access_token"`
Expiration string `json:"expiration"`
}
func getAuthToken(profileName, profilePassword string) (string, error) {
url := "https://api.sthan.io/auth/token"
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
req.Header.Set("profileName", profileName)
req.Header.Set("profilePassword", profilePassword)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var authResp AuthResponse
err = json.Unmarshal(body, &authResp)
if err != nil {
return "", err
}
return authResp.Result.AccessToken, nil
}
func main() {
profileName := os.Getenv("STHAN_PROFILE_NAME")
profilePassword := os.Getenv("STHAN_PROFILE_PASSWORD")
token, err := getAuthToken(profileName, profilePassword)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Authentication token: %s\n", token)
// Store token for later use
os.Setenv("STHAN_AUTH_TOKEN", token)
}
Get authentication token using HttpClient:
using System;
using System.Net.Http;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
public class SthanAuthService
{
private readonly HttpClient _httpClient;
private const string AuthUrl = "https://api.sthan.io/auth/token";
public SthanAuthService()
{
_httpClient = new HttpClient();
}
public async Task<string> GetAuthTokenAsync(string profileName, string profilePassword)
{
var request = new HttpRequestMessage(HttpMethod.Get, AuthUrl);
request.Headers.Add("profileName", profileName);
request.Headers.Add("profilePassword", profilePassword);
var response = await _httpClient.SendAsync(request);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
var apiResponse = JsonSerializer.Deserialize<AuthApiResponse>(content);
return apiResponse.Result.AccessToken;
}
}
public class AuthApiResponse
{
public string Id { get; set; }
public AuthResult Result { get; set; }
public int StatusCode { get; set; }
public bool IsError { get; set; }
public string[] Errors { get; set; }
}
public class AuthResult
{
[JsonPropertyName("access_token")]
public string AccessToken { get; set; }
[JsonPropertyName("expiration")]
public DateTime Expiration { get; set; }
}
// Example usage
var authService = new SthanAuthService();
var token = await authService.GetAuthTokenAsync("your-profile-name", "your-profile-password");
Console.WriteLine($"Authentication token: {token}");
// Store token for later use (e.g., in configuration or cache)
Get authentication token using Laravel HTTP client:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
class SthanAuthService
{
private const AUTH_URL = 'https://api.sthan.io/auth/token';
public function getAuthToken(string $profileName, string $profilePassword): string
{
$response = Http::withHeaders([
'profileName' => $profileName,
'profilePassword' => $profilePassword
])->get(self::AUTH_URL);
if ($response->successful()) {
$token = $response->json()['Result']['access_token'];
// Cache token for 15 minutes (token expiration time)
Cache::put('sthan_auth_token', $token, now()->addMinutes(15));
return $token;
}
throw new \Exception('Authentication failed: ' . $response->status());
}
public function getCachedToken(): ?string
{
return Cache::get('sthan_auth_token');
}
}
// Example usage
$authService = new SthanAuthService();
$token = $authService->getAuthToken(
config('services.sthan.profile_name'),
config('services.sthan.profile_password')
);
echo "Authentication token: {$token}\n";
Get authentication token using Ruby's Net::HTTP:
require 'net/http'
require 'json'
require 'uri'
class SthanAuthService
AUTH_URL = 'https://api.sthan.io/auth/token'.freeze
def initialize(profile_name, profile_password)
@profile_name = profile_name
@profile_password = profile_password
end
def get_auth_token
uri = URI(AUTH_URL)
request = Net::HTTP::Get.new(uri)
request['profileName'] = @profile_name
request['profilePassword'] = @profile_password
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
raise "Authentication failed: #{response.code}" unless response.is_a?(Net::HTTPSuccess)
data = JSON.parse(response.body)
data['Result']['access_token']
end
end
# Example usage
profile_name = ENV['STHAN_PROFILE_NAME'] || 'your-profile-name'
profile_password = ENV['STHAN_PROFILE_PASSWORD'] || 'your-profile-password'
auth_service = SthanAuthService.new(profile_name, profile_password)
token = auth_service.get_auth_token
puts "Authentication token: #{token}"
# Store token for later use
ENV['STHAN_AUTH_TOKEN'] = token
Get authentication token using reqwest:
use reqwest;
use serde::{Deserialize, Serialize};
use std::env;
#[derive(Debug, Deserialize)]
struct AuthResponse {
#[serde(rename = "Id")]
id: String,
#[serde(rename = "Result")]
result: AuthResult,
#[serde(rename = "StatusCode")]
status_code: i32,
}
#[derive(Debug, Deserialize)]
struct AuthResult {
access_token: String,
expiration: String,
}
async fn get_auth_token(
profile_name: &str,
profile_password: &str,
) -> Result> {
let client = reqwest::Client::new();
let response = client
.get("https://api.sthan.io/auth/token")
.header("profileName", profile_name)
.header("profilePassword", profile_password)
.send()
.await?;
let auth_response: AuthResponse = response.json().await?;
Ok(auth_response.result.access_token)
}
#[tokio::main]
async fn main() -> Result<(), Box> {
let profile_name = env::var("STHAN_PROFILE_NAME")
.unwrap_or_else(|_| "your-profile-name".to_string());
let profile_password = env::var("STHAN_PROFILE_PASSWORD")
.unwrap_or_else(|_| "your-profile-password".to_string());
let token = get_auth_token(&profile_name, &profile_password).await?;
println!("Authentication token: {}", token);
// Store token for later use
env::set_var("STHAN_AUTH_TOKEN", &token);
Ok(())
}
Get authentication token using OkHttp:
import okhttp3.OkHttpClient
import okhttp3.Request
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
data class AuthResponse(
@SerializedName("Id") val id: String,
@SerializedName("Result") val result: AuthResult,
@SerializedName("StatusCode") val statusCode: Int
)
data class AuthResult(
@SerializedName("access_token") val accessToken: String,
@SerializedName("expiration") val expiration: String
)
class SthanAuthService {
private val client = OkHttpClient()
private val gson = Gson()
fun getAuthToken(profileName: String, profilePassword: String): String {
val request = Request.Builder()
.url("https://api.sthan.io/auth/token")
.header("profileName", profileName)
.header("profilePassword", profilePassword)
.get()
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw Exception("Authentication failed: ${response.code}")
}
val body = response.body?.string()
?: throw Exception("Empty response body")
val authResponse = gson.fromJson(body, AuthResponse::class.java)
return authResponse.result.accessToken
}
}
}
// Example usage
fun main() {
val profileName = System.getenv("STHAN_PROFILE_NAME") ?: "your-profile-name"
val profilePassword = System.getenv("STHAN_PROFILE_PASSWORD") ?: "your-profile-password"
val authService = SthanAuthService()
val token = authService.getAuthToken(profileName, profilePassword)
println("Authentication token: $token")
// Store token for later use
System.setProperty("STHAN_AUTH_TOKEN", token)
}
Get authentication token using HTTPoison:
defmodule SthanAuthService do
@auth_url "https://api.sthan.io/auth/token"
def get_auth_token(profile_name, profile_password) do
headers = [
{"profileName", profile_name},
{"profilePassword", profile_password}
]
case HTTPoison.get(@auth_url, headers) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
body
|> Jason.decode!()
|> get_in(["Result", "access_token"])
{:ok, %HTTPoison.Response{status_code: status_code}} ->
{:error, "Authentication failed with status: #{status_code}"}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
end
end
# Example usage
profile_name = System.get_env("STHAN_PROFILE_NAME") || "your-profile-name"
profile_password = System.get_env("STHAN_PROFILE_PASSWORD") || "your-profile-password"
case SthanAuthService.get_auth_token(profile_name, profile_password) do
{:error, reason} ->
IO.puts("Error: #{reason}")
token ->
IO.puts("Authentication token: #{token}")
# Store token for later use
System.put_env("STHAN_AUTH_TOKEN", token)
end
Authentication Response Example
When you successfully authenticate, you'll receive a response like this:
{
"Id": "4ab926ac-62dd-407b-8be9-5e5ae20c66ab",
"Result": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54...",
"expiration": "2025-10-27T11:59:19.6097906-07:00"
},
"ClientSessionId": null,
"StatusCode": 200,
"IsError": false,
"Errors": []
}
Key fields to note:
Result.access_token: The JWT bearer token you'll use for API requestsResult.expiration: Token expiration timestamp (15 minutes from issue time)StatusCode: HTTP status code (200 = success)IsError: Boolean flag indicating if the request failedErrors: Array of error messages (empty on success)
Step 2: Verify Addresses
Once you have your authentication token, you can start verifying addresses. Here's how to make verification requests in different programming languages.
Perfect for frontend address validation or Node.js backends:
// Using the token from Step 1
async function verifyAddress(token, addressString) {
// URL encode the address
const encodedAddress = encodeURIComponent(addressString);
const url = `https://api.sthan.io/AddressVerification/Usa/Single/${encodedAddress}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
const data = await response.json();
return data;
}
// Example usage - use token from Step 1
const token = await getAuthToken('your-profile-name', 'your-profile-password');
// Pass the address as a single string
const result = await verifyAddress(token, '6000 j street sacrmento ca');
console.log(result);
// Output:
// {
// "Id": "67890abc-def1-2345-6789-0abcdef12345",
// "Result": {
// "inputAddress": "6000 j street sacrmento ca",
// "fullAddress": "6000 J St, Sacramento, CA 95819-2605",
// "addressLine1": "6000 J St",
// "addressLine2": "",
// "city": "Sacramento",
// "stateCode": "CA",
// "county": "Sacramento",
// "zipCode": "95819",
// "zip4": "2605",
// "algorithmUsed": "cc1",
// "isError": false,
// "errorMessages": []
// },
// "StatusCode": 200,
// "IsError": false,
// "Errors": []
// }
Ideal for data processing, Django, Flask, or FastAPI applications:
import requests
import json
from urllib.parse import quote
def verify_address(token, address_string):
"""
Verify an address using Sthan.io API
Args:
token (str): Authentication token from Step 1
address_string (str): Full address as a single string
Returns:
dict: Verification result
"""
# URL encode the address
encoded_address = quote(address_string)
url = f'https://api.sthan.io/AddressVerification/Usa/Single/{encoded_address}'
headers = {
'Authorization': f'Bearer {token}'
}
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
# Get token from Step 1
token = get_auth_token('your-profile-name', 'your-profile-password')
# Example usage - pass address as a single string
result = verify_address(token, '1199 west shaw avenue fresno california')
print(json.dumps(result, indent=2))
# The API returns:
# {
# "Result": {
# "fullAddress": "1199 W Shaw Ave, Fresno, CA 93711",
# "addressLine1": "1199 W Shaw Ave",
# "city": "Fresno",
# "stateCode": "CA",
# "zipCode": "93711",
# ...
# }
# }
# Batch processing example
addresses = [
'6000 j street sacrmento ca',
'3808 avenue faradiya davis ca',
'543 sanders road cross'
]
verified_addresses = [verify_address(token, addr) for addr in addresses]
For enterprise Java applications:
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriUtils;
import java.nio.charset.StandardCharsets;
public class AddressVerificationService {
private final RestTemplate restTemplate;
private final String authToken;
private static final String API_BASE_URL = "https://api.sthan.io/AddressVerification/Usa/Single/";
public AddressVerificationService(String authToken) {
this.restTemplate = new RestTemplate();
this.authToken = authToken;
}
public AddressVerificationResult verifyAddress(String addressString) {
// URL encode the address
String encodedAddress = UriUtils.encode(addressString, StandardCharsets.UTF_8);
String url = API_BASE_URL + encodedAddress;
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(authToken);
HttpEntity<?> request = new HttpEntity<>(headers);
ResponseEntity<AddressVerificationResult> response =
restTemplate.exchange(url, HttpMethod.GET, request, AddressVerificationResult.class);
return response.getBody();
}
}
// Get auth token from Step 1
SthanAuthService authService = new SthanAuthService();
String token = authService.getAuthToken("your-profile-name", "your-profile-password");
// Usage example with Spring controller
@RestController
@RequestMapping("/api/address")
public class AddressController {
private final AddressVerificationService verificationService;
public AddressController() {
// Get token from auth service and initialize verification service
SthanAuthService authService = new SthanAuthService();
String token = authService.getAuthToken(
System.getenv("STHAN_PROFILE_NAME"),
System.getenv("STHAN_PROFILE_PASSWORD")
);
this.verificationService = new AddressVerificationService(token);
}
@GetMapping("/verify")
public ResponseEntity<AddressVerificationResult> verify(@RequestParam String address) {
AddressVerificationResult result = verificationService.verifyAddress(address);
return ResponseEntity.ok(result);
}
}
For Go applications and microservices:
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
)
type VerificationResponse struct {
ID string `json:"Id"`
Result VerificationResult `json:"Result"`
StatusCode int `json:"StatusCode"`
IsError bool `json:"IsError"`
}
type VerificationResult struct {
InputAddress string `json:"inputAddress"`
FullAddress string `json:"fullAddress"`
AddressLine1 string `json:"addressLine1"`
City string `json:"city"`
StateCode string `json:"stateCode"`
County string `json:"county"`
ZipCode string `json:"zipCode"`
Zip4 string `json:"zip4"`
AlgorithmUsed string `json:"algorithmUsed"`
IsError bool `json:"isError"`
}
func verifyAddress(token, addressString string) (*VerificationResponse, error) {
// URL encode the address
encodedAddress := url.QueryEscape(addressString)
apiURL := fmt.Sprintf("https://api.sthan.io/AddressVerification/Usa/Single/%s", encodedAddress)
req, err := http.NewRequest("GET", apiURL, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var verificationResp VerificationResponse
err = json.Unmarshal(body, &verificationResp)
if err != nil {
return nil, err
}
return &verificationResp, nil
}
func main() {
// Get token from Step 1
token, err := getAuthToken("your-profile-name", "your-profile-password")
if err != nil {
fmt.Printf("Error getting token: %v\n", err)
return
}
// Verify an address
result, err := verifyAddress(token, "6000 j street sacrmento ca")
if err != nil {
fmt.Printf("Error verifying address: %v\n", err)
return
}
fmt.Printf("Input: %s\n", result.Result.InputAddress)
fmt.Printf("Verified: %s\n", result.Result.FullAddress)
fmt.Printf("City: %s, State: %s, ZIP: %s-%s\n",
result.Result.City,
result.Result.StateCode,
result.Result.ZipCode,
result.Result.Zip4)
}
For ASP.NET, Blazor, or .NET Core applications:
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
using System.Web;
public class AddressVerificationService
{
private readonly HttpClient _httpClient;
private const string ApiBaseUrl = "https://api.sthan.io/AddressVerification/Usa/Single/";
public AddressVerificationService(string authToken)
{
_httpClient = new HttpClient();
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", authToken);
}
public async Task<AddressVerificationResult> VerifyAddressAsync(string addressString)
{
// URL encode the address
var encodedAddress = HttpUtility.UrlEncode(addressString);
var url = $"{ApiBaseUrl}{encodedAddress}";
var response = await _httpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var responseJson = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<AddressVerificationResult>(responseJson);
}
}
// Response model classes
public class AddressVerificationResult
{
public string Id { get; set; }
public AddressResult Result { get; set; }
public int StatusCode { get; set; }
public bool IsError { get; set; }
}
public class AddressResult
{
public string InputAddress { get; set; }
public string FullAddress { get; set; }
public string AddressLine1 { get; set; }
public string City { get; set; }
public string StateCode { get; set; }
public string ZipCode { get; set; }
public string Zip4 { get; set; }
}
// Get auth token from Step 1
var authService = new SthanAuthService();
var token = await authService.GetAuthTokenAsync("your-profile-name", "your-profile-password");
// Use token for address verification - pass address as single string
var service = new AddressVerificationService(token);
var result = await service.VerifyAddressAsync("3808 avenue faradiya davis ca");
Console.WriteLine($"Input: {result.Result.InputAddress}");
Console.WriteLine($"Verified: {result.Result.FullAddress}");
For WordPress, Laravel, or PHP applications:
<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
class AddressVerificationService
{
private $authToken;
private $apiBaseUrl = 'https://api.sthan.io/AddressVerification/Usa/Single/';
public function __construct(string $authToken)
{
$this->authToken = $authToken;
}
public function verifyAddress(string $addressString)
{
// URL encode the address
$encodedAddress = urlencode($addressString);
$url = $this->apiBaseUrl . $encodedAddress;
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $this->authToken
])->get($url);
if ($response->successful()) {
return $response->json();
}
throw new \Exception('Address verification failed: ' . $response->body());
}
}
// Get auth token from Step 1
$authService = new SthanAuthService();
$token = $authService->getAuthToken(
config('services.sthan.profile_name'),
config('services.sthan.profile_password')
);
// Usage in controller
use App\Services\{AddressVerificationService, SthanAuthService};
class CheckoutController extends Controller
{
public function validateAddress(Request $request)
{
// Get auth token
$authService = new SthanAuthService();
$token = $authService->getCachedToken() ?? $authService->getAuthToken(
config('services.sthan.profile_name'),
config('services.sthan.profile_password')
);
$service = new AddressVerificationService($token);
// Combine address components into a single string
$addressString = sprintf(
'%s %s %s %s',
$request->input('street'),
$request->input('city'),
$request->input('state'),
$request->input('zip')
);
$result = $service->verifyAddress($addressString);
return response()->json($result);
}
}
For Ruby on Rails or Sinatra applications:
require 'net/http'
require 'json'
require 'uri'
class AddressVerificationService
API_BASE_URL = 'https://api.sthan.io/AddressVerification/Usa/Single/'.freeze
def initialize(auth_token)
@auth_token = auth_token
end
def verify_address(address_string)
# URL encode the address
encoded_address = URI.encode_www_form_component(address_string)
uri = URI("#{API_BASE_URL}#{encoded_address}")
request = Net::HTTP::Get.new(uri)
request['Authorization'] = "Bearer #{@auth_token}"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
raise "Address verification failed: #{response.code}" unless response.is_a?(Net::HTTPSuccess)
JSON.parse(response.body)
end
end
# Get auth token from Step 1
auth_service = SthanAuthService.new(
ENV['STHAN_PROFILE_NAME'] || 'your-profile-name',
ENV['STHAN_PROFILE_PASSWORD'] || 'your-profile-password'
)
token = auth_service.get_auth_token
# Verify an address
verification_service = AddressVerificationService.new(token)
result = verification_service.verify_address('6000 j street sacrmento ca')
puts "Input: #{result['Result']['inputAddress']}"
puts "Verified: #{result['Result']['fullAddress']}"
puts "City: #{result['Result']['city']}, State: #{result['Result']['stateCode']}"
puts "ZIP: #{result['Result']['zipCode']}-#{result['Result']['zip4']}"
For high-performance Rust applications:
use reqwest;
use serde::{Deserialize, Serialize};
use urlencoding::encode;
#[derive(Debug, Deserialize)]
struct VerificationResponse {
#[serde(rename = "Id")]
id: String,
#[serde(rename = "Result")]
result: VerificationResult,
#[serde(rename = "StatusCode")]
status_code: i32,
}
#[derive(Debug, Deserialize)]
struct VerificationResult {
#[serde(rename = "inputAddress")]
input_address: String,
#[serde(rename = "fullAddress")]
full_address: String,
#[serde(rename = "addressLine1")]
address_line1: String,
city: String,
#[serde(rename = "stateCode")]
state_code: String,
#[serde(rename = "zipCode")]
zip_code: String,
zip4: String,
}
async fn verify_address(
token: &str,
address_string: &str,
) -> Result> {
let encoded_address = encode(address_string);
let url = format!("https://api.sthan.io/AddressVerification/Usa/Single/{}", encoded_address);
let client = reqwest::Client::new();
let response = client
.get(&url)
.header("Authorization", format!("Bearer {}", token))
.send()
.await?;
let verification_response: VerificationResponse = response.json().await?;
Ok(verification_response)
}
#[tokio::main]
async fn main() -> Result<(), Box> {
// Get token from Step 1
let token = get_auth_token("your-profile-name", "your-profile-password").await?;
// Verify an address
let result = verify_address(&token, "6000 j street sacrmento ca").await?;
println!("Input: {}", result.result.input_address);
println!("Verified: {}", result.result.full_address);
println!("City: {}, State: {}", result.result.city, result.result.state_code);
println!("ZIP: {}-{}", result.result.zip_code, result.result.zip4);
Ok(())
}
For Android or Kotlin applications:
import okhttp3.OkHttpClient
import okhttp3.Request
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
data class VerificationResponse(
@SerializedName("Id") val id: String,
@SerializedName("Result") val result: VerificationResult,
@SerializedName("StatusCode") val statusCode: Int
)
data class VerificationResult(
@SerializedName("inputAddress") val inputAddress: String,
@SerializedName("fullAddress") val fullAddress: String,
@SerializedName("addressLine1") val addressLine1: String,
@SerializedName("city") val city: String,
@SerializedName("stateCode") val stateCode: String,
@SerializedName("zipCode") val zipCode: String,
@SerializedName("zip4") val zip4: String,
@SerializedName("algorithmUsed") val algorithmUsed: String
)
class AddressVerificationService(private val authToken: String) {
private val client = OkHttpClient()
private val gson = Gson()
private val apiBaseUrl = "https://api.sthan.io/AddressVerification/Usa/Single/"
fun verifyAddress(addressString: String): VerificationResponse {
// URL encode the address
val encodedAddress = URLEncoder.encode(addressString, StandardCharsets.UTF_8.toString())
val url = "$apiBaseUrl$encodedAddress"
val request = Request.Builder()
.url(url)
.header("Authorization", "Bearer $authToken")
.get()
.build()
client.newCall(request).execute().use { response ->
if (!response.isSuccessful) {
throw Exception("Verification failed: ${response.code}")
}
val body = response.body?.string()
?: throw Exception("Empty response body")
return gson.fromJson(body, VerificationResponse::class.java)
}
}
}
// Example usage
fun main() {
// Get token from Step 1
val authService = SthanAuthService()
val token = authService.getAuthToken(
System.getenv("STHAN_PROFILE_NAME") ?: "your-profile-name",
System.getenv("STHAN_PROFILE_PASSWORD") ?: "your-profile-password"
)
// Verify an address
val verificationService = AddressVerificationService(token)
val result = verificationService.verifyAddress("6000 j street sacrmento ca")
println("Input: ${result.result.inputAddress}")
println("Verified: ${result.result.fullAddress}")
println("City: ${result.result.city}, State: ${result.result.stateCode}")
println("ZIP: ${result.result.zipCode}-${result.result.zip4}")
}
For Phoenix or Elixir applications:
defmodule AddressVerificationService do
@api_base_url "https://api.sthan.io/AddressVerification/Usa/Single/"
def verify_address(auth_token, address_string) do
# URL encode the address
encoded_address = URI.encode(address_string)
url = @api_base_url <> encoded_address
headers = [
{"Authorization", "Bearer #{auth_token}"}
]
case HTTPoison.get(url, headers) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
Jason.decode!(body)
{:ok, %HTTPoison.Response{status_code: status_code}} ->
{:error, "Verification failed with status: #{status_code}"}
{:error, %HTTPoison.Error{reason: reason}} ->
{:error, reason}
end
end
end
# Example usage
# Get auth token from Step 1
profile_name = System.get_env("STHAN_PROFILE_NAME") || "your-profile-name"
profile_password = System.get_env("STHAN_PROFILE_PASSWORD") || "your-profile-password"
token = case SthanAuthService.get_auth_token(profile_name, profile_password) do
{:error, reason} ->
IO.puts("Auth error: #{reason}")
System.halt(1)
token ->
token
end
# Verify an address
case AddressVerificationService.verify_address(token, "6000 j street sacrmento ca") do
{:error, reason} ->
IO.puts("Error: #{reason}")
result ->
verification_result = result["Result"]
IO.puts("Input: #{verification_result["inputAddress"]}")
IO.puts("Verified: #{verification_result["fullAddress"]}")
IO.puts("City: #{verification_result["city"]}, State: #{verification_result["stateCode"]}")
IO.puts("ZIP: #{verification_result["zipCode"]}-#{verification_result["zip4"]}")
end
Understanding the API Response
The API returns a structured JSON response containing the verification results and standardized address components:
{
"Id": "67890abc-def1-2345-6789-0abcdef12345",
"Result": {
"inputAddress": "6000 j street sacrmento ca",
"fullAddress": "6000 J St, Sacramento, CA 95819-2605",
"addressLine1": "6000 J St",
"addressLine2": "",
"city": "Sacramento",
"stateCode": "CA",
"county": "Sacramento",
"zipCode": "95819",
"zip4": "2605",
"algorithmUsed": "cc1",
"isError": false,
"errorMessages": []
},
"StatusCode": 200,
"IsError": false,
"Errors": []
}
Key Response Fields
- inputAddress: The original address string you submitted
- fullAddress: The complete, USPS-standardized address
- addressLine1: Street number and street name
- city: City name (standardized)
- stateCode: Two-letter state abbreviation
- county: County name
- zipCode: 5-digit ZIP code
- zip4: ZIP+4 extension for precise delivery
- algorithmUsed: Which verification algorithm was used (e.g., "cc1", "TryGetExactMatch", "fuzzy-auto-poc")
- isError: Whether the verification encountered an error
6. Best Practices for Address Verification
✅ Verify During Data Entry, Not After
Validate addresses in real-time as users type or immediately after form submission. This provides instant feedback and prevents invalid data from entering your system.
✅ Use Address Autocomplete First
Combine address autocomplete with verification. Let users select from suggested addresses as they type, then verify the final selection. This reduces errors and speeds up data entry. Check out our complete guide to implementing address autocomplete in React, Vue, and Angular.
✅ Handle Edge Cases Gracefully
Not every address will validate perfectly. Implement logic to handle:
- New addresses not yet in databases
- Rural routes and PO boxes
- Military addresses (APO/FPO)
- International addresses with varying formats
✅ Cache Results Appropriately
Cache verified addresses to reduce API calls and improve performance. But remember: address data changes over time, so set reasonable TTLs (30-90 days).
✅ Provide Clear User Feedback
When an address can't be verified, explain why and suggest corrections. Don't just show a generic error message.
// Good: Helpful feedback
if (!result.valid) {
if (result.suggestions && result.suggestions.length > 0) {
showMessage('We found a similar address. Did you mean: ' +
result.suggestions[0].formatted);
} else {
showMessage('We couldn\'t verify this address. Please double-check ' +
'the street name and number.');
}
}
✅ Monitor API Usage and Errors
Track your API usage, error rates, and response times. Set up alerts for unusual patterns that might indicate issues.
7. Common Pitfalls to Avoid
❌ Blocking Form Submission on Verification Failure
Don't prevent users from submitting a form if verification fails. Some addresses legitimately won't verify (new construction, etc.). Instead, show a warning and let them confirm their entry.
❌ Over-Relying on Client-Side Validation
Always verify addresses server-side. Client-side validation can be bypassed, and you don't want to expose your API key in frontend code.
❌ Ignoring International Address Formats
If you serve international customers, ensure your validation supports their address formats. A US-only validator will fail for international addresses.
❌ Not Testing with Real-World Data
Test with various address formats: apartments, rural routes, PO boxes, military addresses, and edge cases. Don't just test with clean, perfect addresses.
❌ Forgetting About Performance
API calls add latency. Implement timeouts, handle failures gracefully, and consider async verification for non-critical workflows to avoid blocking users.
Key Takeaways
- Address verification reduces shipping costs, improves conversion rates, and enhances data quality
- Choose an API provider based on coverage, accuracy, performance, and pricing that fits your needs
- Implement verification server-side with proper error handling and user feedback
- Combine autocomplete with verification for the best user experience
- Test thoroughly with real-world address scenarios including edge cases
- Monitor usage and continuously optimize your implementation
8. Conclusion
Address verification is no longer optional—it's a competitive necessity. Whether you're reducing shipping costs, improving conversion rates, or enhancing data quality, a solid address verification strategy delivers measurable ROI.
The implementation examples in this guide give you a head start, but remember: the best verification system is one that fits seamlessly into your user experience while maintaining data accuracy.
Ready to get started? Sign up for Sthan.io and get 100 free address verifications per month—no credit card required. Check out our flexible pricing plans for higher volumes.
Frequently Asked Questions
Ready to Implement Address Verification?
Start verifying addresses with our powerful API. Get 100 free lookups every month.
Related Articles
How to Integrate Address Autocomplete in React, Vue, and Angular
Learn how to implement address autocomplete in React, Vue, and Angular with complete code examples.
Reducing Cart Abandonment with Address Validation
Discover how address validation improves e-commerce conversion rates.
USPS Address Standards Explained
Understanding address formats, abbreviations, and standardization rules.