API reference/consistency
Download a bulk consistency job's results
GET/api/v1/consistency/bulk/{jobId}/results
- authentication
- Secret API key as a bearer token
- billing
- Free.
The result file as CSV: one row per input row, in input order. A run created from an uploaded file carries that file's own columns first, then the four signals as submitted and the country they were measured against, then the comparison.
The comparison columns are signals_requested and signals_answered (;-joined, in the order the legs ran), country_agreement, flags (;-joined), one cell per comparison — phone_address_country, ip_address_country, ip_phone_country, email_ip_disposable_datacenter, email_ip_disposable_anonymous, email_address_free_provider_mail_drop, email_phone_disposable — and distance_km. Last come the few per-product fields those comparisons read, so a difference can be checked against the values that decided it, and credits_used.
A comparison cell reads agree, differ, not_compared, missing_value, low_confidence, or nothing at all. An empty cell means the comparison was never attempted, because the row did not carry both of its signals. The two withheld reasons are written in place of a bare not_compared because they mean different things and a spreadsheet has nowhere else to put them: missing_value is a field the product did not evaluate — which means "not evaluated" and never "no" — and low_confidence is an IP address whose country belongs to the network operator rather than to the person, a VPN exit, a relay or a datacenter egress. distance_km is evidence only and never raises a flag: there is no honest distance at which a person stops being themselves.
signals_requested against signals_answered is also where a row cut short says so: a run that stopped on an empty balance part-way through a row keeps the legs it had already paid for, and that row answers fewer signals than it asked for.
Add ?variant=flagged|unflagged|uncompared to download only the rows a flag was raised on, the rows that were compared and raised none, or the rows too thin to compare; 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. It is streamed row by row exactly as the CSV is. 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, 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 a flag was raised on, the rows compared with none, or the rows fewer than two signals answered for. Defaults to full. One of: full, flagged, unflagged, uncompared. |
| 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/consistency/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.
email,phone,ip,address,country,signals_requested,signals_answered,country_agreement,flags,phone_address_country,ip_address_country,ip_phone_country,email_ip_disposable_datacenter,email_ip_disposable_anonymous,email_address_free_provider_mail_drop,email_phone_disposable,distance_km,email_deliverable,email_disposable,email_free_provider,phone_valid,phone_country,phone_is_disposable,ip_country,ip_risk_level,ip_is_datacenter,ip_is_anonymous,address_valid,address_country,address_is_mail_drop,credits_used [email protected],+442079460018,81.2.69.142,"10 Downing Street, London, SW1A 2AA",GB,ip;phone;address;email,ip;phone;address;email,agree,,agree,agree,agree,not_compared,not_compared,not_compared,not_compared,12.4,true,false,false,true,GB,false,GB,low,false,false,true,GB,false,3
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.