- 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 fields of the single-address response as columns plus the credits it cost. Two structured fields are flattened: sanctions as its codes joined with ;, account_list as kind:name. Left out, because they belong to one live request rather than a row: timezone_matches (needs a browser), seen_by_you (would count the run's own rows), and the opt-in network fields (abuse_contact, network_details, the hostname fields). Fields containing spaces are quoted. Add ?variant=low|medium|high to download only the rows of 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 one risk level. Defaults to full. One of: full, 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/ip/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.
ip,version,reason,network,continent,country,country_name,is_eu,is_eea,privacy_regime,sanctions,fatf_list,region,city,latitude,longitude,location_source,location_confidence,timezone,timezone_source,currency,calling_code,asn,org,asn_type,connection_type,is_mobile,is_satellite,registry,registry_country,allocated_at,is_datacenter,hosting_provider,is_corporate_proxy,corporate_proxy,is_crawler,crawler,crawler_kind,is_blocklisted,blocklist,is_attack_source,attack_source,is_tor,tor_last_seen,is_vpn,is_relay,privacy_service,is_anonymous,account_list,risk_score,risk_level,credits_used 8.8.8.8,4,,8.8.8.0/24,NA,US,United States,false,false,ccpa,,,California,Mountain View,37.4056,-122.0775,database,low,America/Los_Angeles,region,USD,1,15169,Google LLC,hosting,hosting,false,false,arin,US,2023-12-28,true,,false,,false,,,false,,false,,false,,false,false,,false,,40,medium,1
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.