API reference/address

Validate up to 100 addresses in one call

POST/api/v1/address/batch

authentication
Secret API key as a bearer token
billing
Each address bills like a single lookup: 1 credit for a fresh answer that stands as written; addresses that cannot, and 7-day repeats, are free. The call stops cleanly where the balance ends.

Runs the single-address lookup for every item, in input order, under the exact single-lookup billing rules. Every answer comes from the installed datasets, so no item waits on a network call. data.results[] mirrors the single-address response per item and each item's meta carries credits_used and cache_hit.

Each item is either a written address as a plain string, or an object of the same fields the single lookup takes. An item may name its own country, which wins over the list-level one; an item left with no country at all is answered missing_country, free, rather than refused.

Repeats inside the list are looked up once and answer as cache hits — the repeat marker is keyed by the address as the pipeline folds it, so two spellings of one address count as one. The list is walked in order and stops where the balance would run out: running out of credits mid-batch returns the paid partial results with meta.stopped_reason: "insufficient_credits" and processed lower than requested, never discarding billed work. Only a batch whose first lookup is refused answers the typed 402.

A batch counts as one request against the rate limit. deliverability asks the licensed partner about every item; the base and premium credits are gated per item before the lookup, so no paid query is spent on an address that could not be charged.

Batches honour the account's postal suppression list: an address on it is answered from the list without being read again, free, with meta.suppressed: true on that item.

Request body

field type description
addressesrequiredstring[]1 to 100 addresses. Each item is a written address as a string, or an object of the same fields the single lookup takes.
addresses[].addressstring | nullThe whole address written as it would be on an envelope. At most 500 characters.
addresses[].address_line1string | nullThe street line, when the address arrives separated. At most 255 characters.
addresses[].address_line2string | nullAt most 255 characters.
addresses[].organizationstring | nullAt most 200 characters.
addresses[].dependent_localitystring | nullAt most 100 characters.
addresses[].localitystring | nullAt most 100 characters.
addresses[].administrative_areastring | nullAt most 100 characters.
addresses[].postal_codestring | nullAt most 32 characters.
addresses[].po_boxstring | nullAt most 64 characters.
addresses[].countrystring | nullThis item's own country. Wins over the list-level one. At most 2 characters.
countrystring | nullAn ISO 3166-1 alpha-2 code applied to every item that does not name its own. At most 2 characters.
deliverabilitybooleanAsk the licensed partner about every address. While no partner is enabled it answers `deliverability_checked` false at no extra cost. Default: .

Example request

curl -X POST https://spaw.co/api/v1/address/batch \
  -H "Authorization: Bearer sk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
  "addresses": [
    "1600 Amphitheatre Parkway, Mountain View, CA 94043",
    {
      "address_line1": "221B Baker Street",
      "locality": "London",
      "postal_code": "NW1 6XE",
      "country": "GB"
    },
    94043
  ],
  "country": "US"
}'
const response = await fetch('https://spaw.co/api/v1/address/batch', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer sk_live_…',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    "addresses": [
      "1600 Amphitheatre Parkway, Mountain View, CA 94043",
      {
        "address_line1": "221B Baker Street",
        "locality": "London",
        "postal_code": "NW1 6XE",
        "country": "GB"
      },
      94043
    ],
    "country": "US"
  }),
});
const result = await response.json();
import requests

response = requests.post(
    'https://spaw.co/api/v1/address/batch',
    headers={'Authorization': 'Bearer sk_live_…'},
    json={
        'addresses': [
            '1600 Amphitheatre Parkway, Mountain View, CA 94043',
            {
                'address_line1': '221B Baker Street',
                'locality': 'London',
                'postal_code': 'NW1 6XE',
                'country': 'GB'
            },
            94043
        ],
        'country': 'US'
    },
)
result = response.json()
$ch = curl_init('https://spaw.co/api/v1/address/batch');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_live_…', 'Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode([
        'addresses' => [
            '1600 Amphitheatre Parkway, Mountain View, CA 94043',
            [
                'address_line1' => '221B Baker Street',
                'locality' => 'London',
                'postal_code' => 'NW1 6XE',
                'country' => 'GB'
            ],
            94043
        ],
        'country' => 'US'
    ]),
]);
$result = json_decode(curl_exec($ch), true);

Responses

200One result per processed address, plus the batch totals.

{
    "success": true,
    "data": {
        "results": [
            {
                "data": {
                    "valid": true,
                    "reason": null,
                    "country": "US",
                    "street": "Amphitheatre Parkway",
                    "house_number": "1600",
                    "locality": "Mountain View",
                    "administrative_area": "CA",
                    "postal_code": "94043",
                    "address_type": "street",
                    "risk_score": 0,
                    "risk_level": "low"
                },
                "meta": {
                    "credits_used": 1,
                    "cache_hit": false
                }
            },
            {
                "data": {
                    "valid": true,
                    "reason": null,
                    "country": "GB",
                    "street": "Baker Street",
                    "house_number": "221B",
                    "locality": "London",
                    "postal_code": "NW1 6XE",
                    "address_type": "street",
                    "risk_score": 0,
                    "risk_level": "low"
                },
                "meta": {
                    "credits_used": 1,
                    "cache_hit": false
                }
            },
            {
                "data": {
                    "valid": false,
                    "reason": "missing_street",
                    "country": "US",
                    "street": null,
                    "postal_code": "94043",
                    "risk_score": null,
                    "risk_level": null
                },
                "meta": {
                    "credits_used": 0,
                    "cache_hit": false
                }
            }
        ]
    },
    "meta": {
        "requested": 3,
        "processed": 3,
        "credits_used": 2,
        "credits_remaining": 8,
        "stopped_reason": null,
        "request_id": "req_01m1kgdrtqdvwnks99vfgx2rcw"
    }
}

401The key is missing, malformed, or revoked.

{
    "success": false,
    "error": {
        "code": "UNAUTHENTICATED",
        "message": "Provide a valid API key as a bearer token.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

402The balance is empty. The lookup did not run.

{
    "success": false,
    "error": {
        "code": "INSUFFICIENT_CREDITS",
        "message": "Your credit balance is empty.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

422The request body could not be validated; `error.errors` lists the fields.

{
    "success": false,
    "error": {
        "code": "VALIDATION_FAILED",
        "message": "The email field is required.",
        "errors": {
            "email": [
                "The email field is required."
            ]
        },
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

429Over 5 requests per second for the key. Retry after the limit resets.

{
    "success": false,
    "error": {
        "code": "RATE_LIMITED",
        "message": "Too many requests. Retry after the limit resets.",
        "request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
    }
}

Error codes

Failures answer { success: false, error: { code, message, request_id } }. Each code has its own page.

markdown version·openapi.json