- authentication
- Secret API key as a bearer token
- billing
- Free.
The result file as CSV: one row per input address, in input order, with the address as submitted, every field of the single-address response as a column, the datasets behind the answer, the credits the row cost, and whether the account's suppression list answered it (suppressed). A run created from an uploaded file carries that file's own columns first. Sources are joined by ; as dataset@version, risk signals as signal:weight, the confirmation map as part:source and the changes by their names; formatted writes its lines on one line, joined by , . Fields containing spaces or commas are quoted. Add ?variant=valid|invalid|low|medium|high to download only the rows that stand as written or do not, or one risk level; the default full returns everything. Available once the job is completed, or cancelled or failed with at least one processed row — those rows were billed, so they stay downloadable. A job still running answers 409 RESULTS_NOT_READY, a cancelled job with nothing processed 409 JOB_CANCELLED, and a failed job with nothing processed 409 JOB_FAILED.
format=json answers the same rows, filtered the same way, as objects keyed by the result file's own header instead of a CSV attachment: { "success": true, "data": { "job": …, "results": [ … ] }, "meta": { "variant", "request_id" } }. It is streamed row by row exactly as the CSV is, so a 100,000-row run costs no more to answer either way. A CSV cell carries no type, so only the two the writer encodes come back typed: an empty cell is null and true/false are booleans. Everything else is the string as written — a number is never silently made numeric, because postcodes, phone numbers and house numbers lose their leading zeros that way — and the columns of an uploaded file come back exactly as they were uploaded.
Parameters
| name | in | type | description |
|---|---|---|---|
| jobIdrequired | path | integer | |
| variant | query | string | Restrict the file to the rows that stand as written or do not, or to one risk level. Defaults to full. One of: full, valid, invalid, low, medium, high. |
| format | query | string | `csv` streams the file as an attachment; `json` streams the same rows as objects. One of: csv, json. Default: csv. |
Example request
curl https://spaw.co/api/v1/address/bulk/{jobId}/results \
-H "Authorization: Bearer sk_live_…"This endpoint has no console on its page. It answers with records from your own account, often by an id only you have, rather than about a value you can type here. The dashboard lists the same rows.
Responses
200The result rows, as a CSV attachment or as streamed JSON.
address,valid,reason,country,country_name,continent,is_eu,is_eea,privacy_regime,formatted,formatted_lines,formatted_local,organization,building,street,house_number,unit,po_box,dependent_locality,locality,administrative_area,postal_code,postal_code_formatted,postal_code_valid,postal_code_type,postcode_status,locality_matches_postcode,administrative_area_matches_postcode,address_type,address_type_source,is_po_box,is_private_mailbox,exists,match_level,register,register_coverage,premise_key,building_use,is_multi_unit,unit_check,street_suggestion,latitude,longitude,location_source,companies_registered,is_mail_drop,mail_drop_provider,mail_drop_source,deliverability_checked,is_deliverable,is_cmra,is_vacant,is_residential,confirmation,changes,looks_placeholder,risk_score,risk_level,risk_signals,ok_to_ship,blocked_by,sources,credits_used,suppressed "1600 Amphitheatre Parkway, Mountain View, CA 94043",true,,US,United States,NA,false,false,ccpa,"1600 Amphitheatre Parkway, MOUNTAIN VIEW, CA 94043","1600 Amphitheatre Parkway;MOUNTAIN VIEW, CA 94043",,,,Amphitheatre Parkway,1600,,,,Mountain View,CA,94043,94043,true,zip,,,,street,address_rules,false,,,,,,239f04782171457b,,,,,,,,,,,,false,,,,,postal_code:pattern;street:;house_number:;locality:;administrative_area:,,false,0,low,,true,,address-formats@2026-09-16;address-rules@2026-09-16,1,false
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"
}
}404No such record on this account.
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "No record with that id on this account.",
"request_id": "req_01m1kgdm4xngzmbmff68g94w0c"
}
}409The job is still running (`RESULTS_NOT_READY`), or was cancelled or failed before any row was processed (`JOB_CANCELLED`, `JOB_FAILED`).
{
"success": false,
"error": {
"code": "RESULTS_NOT_READY",
"message": "The results are not ready yet.",
"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.