Skip to content

API reference/address

Download a bulk address job's results

GET/api/v1/address/bulk/{jobId}/results

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
jobIdrequiredpathinteger
variantquerystringRestrict 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.
formatquerystring`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_…"
const response = await fetch('https://spaw.co/api/v1/address/bulk/{jobId}/results', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer sk_live_…',
  },
});
const result = await response.json();
import requests

response = requests.get(
    'https://spaw.co/api/v1/address/bulk/{jobId}/results',
    headers={'Authorization': 'Bearer sk_live_…'},
)
result = response.json()
$ch = curl_init('https://spaw.co/api/v1/address/bulk/{jobId}/results');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ['Authorization: Bearer sk_live_…'],
]);
$result = json_decode(curl_exec($ch), true);
from spaw import Client

client = Client('sk_live_…')
result = client.download_address_bulk_results(job_id)
import Spaw from 'spaw';

const spaw = new Spaw({ apiKey: 'sk_live_…' });
const result = await spaw.downloadAddressBulkResults(jobId);
use Spaw\Client;

$spaw = new Client('sk_live_…');
$result = $spaw->downloadAddressBulkResults($jobId);

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.

markdown version·openapi.json