# 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.
- Group: Address

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 | Required | Description |
| --- | --- | --- | --- |
| `addresses` | string[] | yes | 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[].address` | string | null | no | The whole address written as it would be on an envelope. At most 500 characters. |
| `addresses[].address_line1` | string | null | no | The street line, when the address arrives separated. At most 255 characters. |
| `addresses[].address_line2` | string | null | no | At most 255 characters. |
| `addresses[].organization` | string | null | no | At most 200 characters. |
| `addresses[].dependent_locality` | string | null | no | At most 100 characters. |
| `addresses[].locality` | string | null | no | At most 100 characters. |
| `addresses[].administrative_area` | string | null | no | At most 100 characters. |
| `addresses[].postal_code` | string | null | no | At most 32 characters. |
| `addresses[].po_box` | string | null | no | At most 64 characters. |
| `addresses[].country` | string | null | no | This item's own country. Wins over the list-level one. At most 2 characters. |
| `country` | string | null | no | An ISO 3166-1 alpha-2 code applied to every item that does not name its own. At most 2 characters. |
| `deliverability` | boolean | no | Ask the licensed partner about every address. While no partner is enabled it answers `deliverability_checked` false at no extra cost. Default: . |

## Example request

```bash
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"
}'
```

## Responses

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

```json
{
    "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"
    }
}
```

### 401 — The key is missing, malformed, or revoked.

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

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

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

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

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

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

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

## Error codes

- `UNAUTHENTICATED` — https://spaw.co/docs/errors/UNAUTHENTICATED
- `VALIDATION_FAILED` — https://spaw.co/docs/errors/VALIDATION_FAILED
- `INSUFFICIENT_CREDITS` — https://spaw.co/docs/errors/INSUFFICIENT_CREDITS
- `RATE_LIMITED` — https://spaw.co/docs/errors/RATE_LIMITED

---

Canonical page: https://spaw.co/docs/api/lookup-address-batch · OpenAPI document: https://spaw.co/openapi.json · All endpoints: https://spaw.co/docs/api
