Docs / Lookup API reference · 6 min
Lookup API reference
The POST contract every integration speaks: request, response fields, errors, and the fail-open rule.
The endpoint
Every workspace gets one lookup URL, shown on the dashboard home page. It is the only endpoint an integration needs: your tracker POSTs the inbound caller number to it before the call routes, and the response says allow or block.
POSThttps://api.callersift.com/v1/your-workspace
- Your exact URL is on the home page; the last segment is your workspace slug.
- Form-encoded and JSON bodies both work.
- Typical answer time is milliseconds; cached numbers answer fastest.
Authentication
- Send your API key in the X-Api-Key header, or as an api_key field in the body. Either works; the header keeps keys out of body logs.
- Keys are minted and rotated on the home page without downtime: see the API keys and rotation guide.
- Treat the key like a password. Anyone holding it can spend your lookups.
Request
| Field | Required | Description |
|---|---|---|
| caller_number | required | The inbound caller’s number, US or Canada. E.164 format (+15551234567) is safest; most tracker merge tags emit it already. Numbers from outside the US and Canada answer verdict block, marked out_of_region. |
| api_key | required | Your API key. Send it as this body field or as an X-Api-Key header instead; a request carrying neither answers 401. |
curl -X POST https://api.callersift.com/v1/your-workspace \ -H "X-Api-Key: YOUR_KEY" \ -d "caller_number=+15551234567"
Sending JSON? Always include Content-Type: application/json, or the body is read as a form post and the caller number is missed. The bare curl example uses a form body, which needs no header.
Body formats and authentication
The endpoint accepts two body formats. Form-encoded (application/x-www-form-urlencoded) needs no Content-Type header and is what plain webhook fields produce. JSON works everywhere too, but MUST be sent with Content-Type: application/json; without that header the body is read as a form post, the caller number is missed, and the call defaults to allow unscreened.
Authenticate one of two ways, never both: an api_key field in the body, or an X-Api-Key request header. The header keeps your key out of request-body logs, so prefer it wherever your platform lets you set headers.
form body (no header needed)
caller_number=+15551234567&api_key=fck_your_key
JSON body (header required)
Content-Type: application/json
{
"caller_number": "+15551234567",
"api_key": "fck_your_key"
}Response
The response is a small JSON object. Route the call on verdict; everything else is context for humans and reports. Behind it, a multi-source intelligence pipeline scores the line in real time, and a shared verdict database answers known numbers instantly.
| Field | Values | What it means |
|---|---|---|
| verdict | allowblock | The decision. The only field your routing rule needs. |
| verdict_code | 1 · 0 | The same decision as a number (1 allow, 0 block), for routers whose condition blocks only compare numeric values. |
| line_type | mobile, landline, fixedVoip, nonFixedVoip, tollFree, out_of_region, listed, velocity, reported, … | The carrier classification of the number, or a CallerSift signal: fixedVoip (a business phone system at a real service address, allowed), nonFixedVoip (an app-issued virtual number such as Google Voice or TextNow, blocked), out_of_region (not US/Canada), listed (your allow/block list), velocity (dialer pattern), reported (network fraud report). Exact labels vary slightly by data source; route on verdict, not on this. |
| reason | text | A human-readable explanation of the verdict, the same text you see in the lookups view. |
| source | livecache | live scored the number against carrier data on this request; cache answered instantly from a recent verdict. |
| intel | object · null | The raw line-type intelligence behind the verdict, for your own logging. |
allow
{
"verdict": "allow",
"verdict_code": 1,
"line_type": "mobile",
"reason": "Mobile line: real handset traffic",
"source": "live",
"intel": { … }
}block
{
"verdict": "block",
"verdict_code": 0,
"line_type": "nonFixedVoip",
"reason": "App-based virtual number (Google Voice, TextNow and similar): not a real phone line",
"source": "cache",
"intel": { … }
}Errors and the fail-open rule
| Status | Meaning | Route the call? |
|---|---|---|
| 200 | A verdict. Route on it. | On the verdict |
| 400 | No caller_number in the body. The response still carries verdict allow. | Allow |
| 401 | Missing or wrong API key. Check the key on the home page and your header or body field. | Allow |
| 402 | Screening is paused over billing. The JSON body carries a machine code (subscription_inactive or balance_exhausted) and a message; fix billing under Settings → Plan and lookups resume instantly. | Allow |
| 429 | Rate limited. No retry needed; the next call scores normally. | Allow |
Design your routing so anything other than verdict block, including timeouts and network errors, routes the call normally. CallerSift is built fail-open: an outage on the scoring path must never block a genuine caller. The one deliberate stop is 402, billing has lapsed, so lookups pause until it is fixed in the dashboard.
Wire it into your platform
- TrackDrive and Ringba: step-by-step in Point your call tracker at the lookup URL.
- Retreaver: see Connect Retreaver.
- Anything else that can fire a webhook per inbound call works the same way: POST, read verdict, route.
- Prove the path end to end with Send a test lookup before real traffic rides on it.