Educational

Complete Guide to Address Verification APIs in 2026

Everything you need to know about address verification APIs - from basic concepts to advanced implementation strategies with code examples.

sthan.io Team
sthan.io Team
October 28, 2025 · Updated March 7, 2026 · 12 min read

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 address this 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 a practical step toward cleaner data and fewer failed deliveries.

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)
Did you know? The USPS processes over 472 million pieces of mail every day. Standardized addresses help ensure your mail reaches its destination efficiently.

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 showing how it handles imperfect input:

Correcting Misspelled Street Names & Cities

INPUT 1345 avvenue of americas new york ny
OUTPUT 1345 Avenue Of The Americas, New York, NY 10105-0302

INPUT 6000 j street sacrmento ca
OUTPUT 6000 J St, Sacramento, CA 95819-2605

INPUT 325 w broaddwey # m ny 10013
OUTPUT 325 W Broadway # M, New York, NY 10013-1820

Filling in Missing State & ZIP Codes

INPUT 543 sanders road cross
OUTPUT 543 Sanders Rd, Cross, SC 29436

INPUT 1199 w shaw avenue fresno
OUTPUT 1199 W Shaw Ave, Fresno, CA 93711

Handling Abbreviated & Expanded Forms

The API intelligently handles both abbreviated and expanded forms of street types, directions, and states:

INPUT (Expanded) 1199 west shaw avenue fresno california
OUTPUT (Standardized) 1199 W Shaw Ave, Fresno, CA 93711

INPUT (Abbreviated) 6000 j st sacramento ca
OUTPUT (Standardized) 6000 J St, Sacramento, CA 95819-2605
Smart Standardization: Whether you input "Street" or "St", "Avenue" or "Ave", "West" or "W", "California" or "CA"—the API understands and standardizes to USPS format automatically.

Restructuring Out-of-Order Addresses

INPUT ca 94103 san francisco 1455 market st
OUTPUT 1455 Market St, San Francisco, CA 94103-1331

INPUT los angeles ca 6801 hollywood blvd
OUTPUT 6801 Hollywood Blvd, Los Angeles, CA 90028-6101

INPUT 1345 americas avenue NY
OUTPUT 1345 Avenue Of The Americas, New York, NY 10105-0302
Key Capabilities Demonstrated:
  • 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.

Hypothetical Example: E-commerce Impact

Consider a mid-sized e-commerce company processing 50,000 orders per month. Based on industry averages, implementing address verification could yield results like:

  • Failed deliveries reduced from ~3-5% to under 1%
  • Significant annual savings on re-shipping and returns
  • Improved checkout conversion rates
  • Higher customer satisfaction scores

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: 123
Street 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: Match Against a Comprehensive US Address Dataset

The parsed address is matched against a comprehensive dataset of US addresses. A clean input resolves directly; an input with typos, missing pieces, or unusual formatting is matched to the closest real candidate.

Step 3: Validate — Identity Is Sacred, Labels Are Correctable

Every candidate passes a gate that separates the parts that identify an address from the parts that merely label it:

Sacred — must match exactly
  • House number
  • Street name & numeric ordinal (15th ≠ 17th)
  • Directionals (N ≠ S)
  • State
If a candidate would change any of these, it is rejected — never substituted.
Correctable — fixed and disclosed
  • City spelling
  • ZIP / ZIP+4
  • Street type & formatting
  • Minor street-name typos
Every correction is reported, never applied silently.
Nothing is corrected silently. The response's per-component matchCode marks each part Matched, Corrected, Inferred, or Unmatched, and matchTier (Exact / Near / Approximate) summarises the confidence — so you always see exactly what changed.

Step 4: Choose How Hard to Try — Match Modes

You set the substitution ceiling per request with the match parameter:

  • strict — verbatim only; returns a result only when nothing needed correcting.
  • balanced (default) — allows a single disclosed correction.
  • fuzzy — allows multiple disclosed corrections (typos, plus missing city/state/ZIP).
  • speculative — widest typo tolerance for best-effort recovery; results are flagged as no-guarantee.

A looser mode never hides a change — it only raises the ceiling on how many disclosed corrections it will accept. The identity components above stay sacred in every mode.

Step 5: Confirm Deliverability

The verification endpoint checks the standardized address against postal delivery records and returns a deliverableStatus:

  • Confirmed — a confirmed delivery point.
  • ConfirmedPrimaryOnly — the building is confirmed; the unit/suite is unverified.
  • NotDeliverable — postal records show it is not deliverable.
  • Unknown — a recognized address with no delivery-point confirmation available.

Standardization & Enrichment

Postal standardization (USPS Pub 28)
  • Proper abbreviations (Avenue → AVE)
  • Standard casing
  • ZIP+4 where available
  • Carrier route
Match metadata returned
  • Per-component matchCode
  • matchTier + confidence
  • deliverableStatus
  • footnotes (what changed & why)
The honest part: if an address can't be confidently matched within the chosen mode, the API declines (404) rather than returning a different address that merely looks plausible. You get a correct address — with every change disclosed — or an honest “not found,” never a confidently-wrong one.

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; published accuracy and coverage figures
Performance Response-time and uptime SLAs; consistent latency under load
Pricing Cost per lookup; volume discounts; free tier availability
Features Autocomplete, parsing, geocoding, international support
Developer Experience Clear documentation, SDKs, code samples, support quality
Tip: Start with a provider that offers a generous free tier so you can test thoroughly before committing. sthan.io offers 100 free lookups per month—perfect for development and testing.

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.

Free Tier Available: Start with 100 free address verifications per month. No credit card required. Perfect for development, testing, or small-scale applications. Check the pricing page for paid plans with higher volumes.

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 requests
  • Result.expiration: Token expiration timestamp (15 minutes from issue time)
  • StatusCode: HTTP status code (200 = success)
  • IsError: Boolean flag indicating if the request failed
  • Errors: Array of error messages (empty on success)
Token Management: Authentication tokens expire after 15 minutes. Implement token caching with automatic refresh logic in production applications to avoid unnecessary authentication calls while ensuring you always use valid tokens.

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/v2/address-verification/usa/balanced/${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 (match=balanced):
// {
//   "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": "Sacramento, CA 95819-2605",
//     "city": "Sacramento",
//     "stateCode": "CA",
//     "county": "Sacramento",
//     "zipCode": "95819",
//     "zip4": "2605",
//     "dpvConfirmation": "Y",
//     "deliverableStatus": "Confirmed",
//     "matchMode": "Balanced",
//     "matchTier": "Near",
//     "confidence": 0.9,
//     "matchCode": {
//       "houseNumber": "Matched", "street": "Matched", "unit": "NotApplicable",
//       "city": "Corrected", "state": "Matched", "zipCode": "Inferred", "zip4": "Inferred"
//     },
//     "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/v2/address-verification/usa/balanced/{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",
#     "deliverableStatus": "Confirmed",
#     "matchTier": "Exact",
#     "confidence": 1.0,
#     "matchCode": { "houseNumber": "Matched", "street": "Matched", ... },
#     ...
#   }
# }

# Batch processing example
addresses = [
    '6000 j street sacrmento ca',
    '1345 avvenue of americas new york ny',
    '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/v2/address-verification/usa/balanced/";

    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"`
    DeliverableStatus string  `json:"deliverableStatus"`
    MatchTier         string  `json:"matchTier"`
    Confidence        float64 `json:"confidence"`
    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/v2/address-verification/usa/balanced/%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/v2/address-verification/usa/balanced/";

    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("1345 avvenue of americas new york ny");

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/v2/address-verification/usa/balanced/';

    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/v2/address-verification/usa/balanced/'.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/v2/address-verification/usa/balanced/{}", 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("deliverableStatus") val deliverableStatus: String,
    @SerializedName("matchTier") val matchTier: String,
    @SerializedName("confidence") val confidence: Double
)

class AddressVerificationService(private val authToken: String) {
    private val client = OkHttpClient()
    private val gson = Gson()
    private val apiBaseUrl = "https://api.sthan.io/v2/address-verification/usa/balanced/"

    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/v2/address-verification/usa/balanced/"

  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
Security Note: Never expose your API key in frontend code. Always make API calls from your backend server and use environment variables to store your API key.

Try it live

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": "Sacramento, CA 95819-2605",
    "city": "Sacramento",
    "stateCode": "CA",
    "county": "Sacramento",
    "zipCode": "95819",
    "zip4": "2605",
    "dpvConfirmation": "Y",
    "deliverableStatus": "Confirmed",
    "matchMode": "Balanced",
    "matchTier": "Near",
    "confidence": 0.9,
    "matchCode": {
      "houseNumber": "Matched",
      "street": "Matched",
      "unit": "NotApplicable",
      "city": "Corrected",
      "state": "Matched",
      "zipCode": "Inferred",
      "zip4": "Inferred"
    },
    "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 / addressLine2: The street line, and the city/state/ZIP line
  • city, stateCode, county, zipCode, zip4: The standardized address components
  • deliverableStatus: Whether the address is deliverable—Confirmed, ConfirmedPrimaryOnly (building confirmed, unit not), NotDeliverable, or Unknown
  • dpvConfirmation: The raw USPS Delivery Point Validation code behind deliverableStatus
  • matchMode: The match mode used—strict, balanced, fuzzy, or speculative
  • matchTier: How the address matched—Exact, Near, Approximate, or Speculative
  • confidence: A 0–1 score for the match
  • matchCode: The per-component verdict (Matched, Corrected, Inferred, Unmatched, NotApplicable) for each part of the address—so you can see exactly what was changed
  • isError: Whether the verification encountered an error
Modes & matchCode: Use matchMode (strict → balanced → fuzzy → speculative) to control how aggressively the API recovers imperfect input, and read matchCode to see exactly which components were matched, corrected, or inferred. Identity components—house number, directionals, state, and the street name—are never silently substituted.

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 right verification system is one that fits naturally 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.

Share This Article

Frequently Asked Questions

An address verification API is a service that validates, standardizes, and enriches address data in real-time. It checks whether a given address exists and is deliverable by comparing it against authoritative databases maintained by postal services like USPS. The process involves parsing the address into components, validating against databases, and standardizing the format according to postal service standards.
Address verification API pricing varies by provider. sthan.io offers 100 free address verifications per month with no credit card required, making it perfect for development and testing. Paid plans are available for higher volumes. The cost per lookup typically decreases with volume, and most providers offer tiered pricing based on monthly usage.
Address verification APIs are language-agnostic and work with any programming language that can make HTTP requests. Common implementations include JavaScript/Node.js, Python, Java, Go, C#/.NET, PHP, Ruby, Rust, Kotlin, and Elixir. Most providers offer RESTful APIs with JSON responses that integrate easily with any technology stack.
Accuracy depends on the data sources used. APIs that combine multiple authoritative sources — such as USPS databases, Census geocoding, and a comprehensive address dataset with fuzzy matching — recover more misspelled or incomplete addresses than single-source lookups. CASS-certified providers meet USPS standards for address standardization.
CASS (Coding Accuracy Support System) certification is a USPS standard that ensures address validation software meets specific accuracy requirements. If you need to qualify for postal discounts or require the highest level of USPS-compliant address standardization, you should use a CASS-certified API. For general address validation and standardization, CASS certification is beneficial but not always required.
The ability to verify international addresses depends on the API provider. Some providers specialize in US addresses only (using USPS data), while others offer global coverage. When evaluating providers, check their data coverage for your target countries and ensure they support the specific address formats and postal standards for those regions. sthan.io currently supports US address verification and India address autocomplete, with plans to expand to additional countries.
Integrating address verification typically involves two steps: 1) Obtain an authentication token using your API credentials, and 2) Make verification requests by sending addresses to the API endpoint. Most APIs use REST architecture with JSON responses. You can implement verification during form submission (real-time validation) or batch process existing addresses. The integration usually takes less than an hour for basic implementation.
Address validation and verification are often used interchangeably, but technically: validation checks if an address follows the correct format and structure, while verification confirms the address actually exists and is deliverable by checking against authoritative postal databases. Modern APIs typically do both - they validate the format AND verify deliverability in a single operation.
Always verify addresses server-side for security and accuracy. Client-side validation can be used for basic format checking and improved user experience, but should never replace server-side verification. Server-side verification protects your API keys, prevents tampering, ensures data integrity, and provides authoritative validation. A hybrid approach using client-side autocomplete with server-side verification offers the best user experience and data quality.
Address verification reduces shipping costs by preventing failed deliveries and returns. Each failed delivery can cost $10-$30 in re-shipping fees and customer service overhead. By ensuring addresses are valid and deliverable before shipping, businesses can reduce failed delivery rates from 3-5% to under 1%. For high-volume shippers, these savings can add up to significant annual cost reductions.

Ready to Implement Address Verification?

Start verifying addresses with the sthan.io API. Get 100 free lookups every month.

sthan.io Team
Written by sthan.io Team

The sthan.io engineering team builds and maintains address verification, parsing, geocoding, and autocomplete APIs. We work with USPS postal addressing standards and spatial data systems to help businesses improve address data quality and reduce failed deliveries.

Learn more about us