API
API reference
On this page
Authentication
You need credits: the 20 a month included with an active Pro account, or credits bought on your account page. An account with neither receives 403 pro_required.
This key is shown only once. Save it securely on your server.
Create an API key in your account and copy the value shown once. Configure NOCALL_API_KEY as a secret on your server. Use HTTPS; never include the key in browser code, repositories, screenshots or logs.
Send the full key in Authorization: Bearer, with one space after Bearer. Do not use X-API-Key or put the key in the URL.
On /v1/data/* + /v2/*, a valid key replaces browser ByteGuard proof. Expiry, revocation, subscription, credits and rate limits still apply. It does not authorize other routes. openapi.json and products are public.
Authorization: Bearer <NOCALL_API_KEY>Your first lookup
All 44 tools are available through the API: call POST /v2/<tool-id>, or POST /v2/tools with the tool field in the body. Each tool has its own JSON body, documented in its guide. data.result contains the tool result. Use the identifiers in the table.
Generate a fresh Idempotency-Key for each new operation. Keep that key only to retry the same operation with the same input.
REQUEST_ID="$(uuidgen)" && [ -n "$REQUEST_ID" ] &&
curl --request POST 'https://api.nocall.io/v2/tools' \
--header "Authorization: Bearer $NOCALL_API_KEY" \
--header 'Content-Type: application/json' \
--header "Idempotency-Key: $REQUEST_ID" \
--data '{"tool":"who-calls","phone":"+12025550123","country":"US"}'import json
import os
import urllib.request
import uuid
api_key = os.environ.get('NOCALL_API_KEY')
if not api_key:
raise SystemExit('Set NOCALL_API_KEY')
request = urllib.request.Request(
'https://api.nocall.io/v2/tools',
method='POST',
data=json.dumps({'tool': 'who-calls', 'phone': '+12025550123', 'country': 'US'}).encode(),
headers={
'Authorization': 'Bearer ' + api_key,
'Content-Type': 'application/json',
'Idempotency-Key': str(uuid.uuid4()),
},
)
with urllib.request.urlopen(request, timeout=30) as response:
result = json.load(response)
print(result['data']['result'], result['meta']['unitsCharged'])import { randomUUID } from 'node:crypto';
const requestId = randomUUID();
const apiKey = process.env.NOCALL_API_KEY;
if (!apiKey) throw new Error('Set NOCALL_API_KEY');
const response = await fetch('https://api.nocall.io/v2/tools', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + apiKey,
'Content-Type': 'application/json',
'Idempotency-Key': requestId,
},
body: JSON.stringify({ tool: 'who-calls', phone: '+12025550123', country: 'US' }),
});
const result = await response.json();
if (!response.ok) throw new Error(result.error?.code ?? 'request_failed');
console.log(result.data.result, result.meta.unitsCharged);API v2 · tools
All 44 tools are available through the API: call POST /v2/<tool-id>, or POST /v2/tools with the tool field in the body. Each tool has its own JSON body, documented in its guide. data.result contains the tool result. Use the identifiers in the table.
| tool | Purpose | POST | Synthetic example |
|---|---|---|---|
| who-calls | Who is calling me? | /v2/who-calls | {"phone":"+12025550123","country":"US"} |
| phone-exposure | Has my number been leaked? | /v2/phone-exposure | {"phone":"+12025550123","country":"US"} |
| phone-intelligence | Phone intelligence | /v2/phone-intelligence | {"phone":"+12025550123","country":"US"} |
| phone-risk | Phone risk | /v2/phone-risk | {"phone":"+12025550123","country":"US"} |
| carrier-lookup | Carrier lookup | /v2/carrier-lookup | {"phone":"+12025550123","country":"US"} |
| verified-business | Verified business reverse lookup | /v2/verified-business | {"phone":"+12025550123","country":"US"} |
| phone-formats | Phone number formats | /v2/phone-formats | {"phone":"+34912345678","country":"ES"} |
| callback-cost | How much does it cost to call back? | /v2/callback-cost | {"phone":"806123456","country":"ES"} |
| prefix-origin | Where is this area code from? | /v2/prefix-origin | {"phone":"910","country":"ES"} |
| number-validator | Phone number validator and formatter | /v2/number-validator | {"phone":"+12025550123","country":"US"} |
| line-type | Is it a mobile or a landline? | /v2/line-type | {"phone":"+34600111222","country":"ES"} |
| premium-rate | Is it a premium-rate number? | /v2/premium-rate | {"phone":"806","country":"ES"} |
| wangiri | Wangiri check: is this missed call a scam? | /v2/wangiri | {"phone":"+216","country":"ES"} |
| commercial-400 | Is this sales call legal? | /v2/commercial-400 | {"phone":"+34400000000","country":"ES"} |
| number-research | Research a number with AI | /v2/number-research | {"phone":"+12025550123","country":"US","language":"en"} |
| dial-code | Asked to dial a code? | /v2/dial-code | {"code":"**21*+34600000000#","country":"ES"} |
| call-scam-check | Is this call a scam? | /v2/call-scam-check | {"answers":{"impersonation":true,"sms_code":true,"pressure":true},"country":"ES"} |
| sms-check | Check if a text message is a scam | /v2/sms-check | {"message":"Your parcel is held. Pay the fee at https://example.invalid/pay","sender":"Correos","language":"en","country":"GB"} |
| sms-brand | Is this text from a brand real? | /v2/sms-brand | {"brand":"correos","link":"https://correos-envio.example.invalid/pago","country":"ES"} |
| sms-sender | Who sent me this text? | /v2/sms-sender | {"sender":"Correos","country":"ES"} |
| sms-code | Asked for a code sent by SMS? | /v2/sms-code | {"unrequested":true,"asked":true,"sensitive":true,"shared":false} |
| sms-report | Where to report a scam text | /v2/sms-report | {"sender":"Correos","tapped":false,"gaveData":false,"country":"ES"} |
| sms-campaigns | SMS scam campaigns | /v2/sms-campaigns | {} |
| sms-redact | Remove your data from a text | /v2/sms-redact | {"message":"BBVA: su tarjeta 4111 1111 1111 1111 ha sido bloqueada. Llame al +34 612 34 56 78 o entre en https://bbva-seguro.com/login"} |
| callback-number | Should I call the number in this message? | /v2/callback-number | {"text":"Your account is locked. Call us now on 0909 879 0000 or +216 71 123 456","country":"GB"} |
| prefix-directory | Prefixes | /v2/prefix-directory | {"country":"ES","serviceClass":"premium","page":1,"limit":3} |
| operator-directory | Operators | /v2/operator-directory | {"country":"ES","operator":"Movistar"} |
| calling-codes | International codes | /v2/calling-codes | {"query":"216","language":"en"} |
| spam-directory | Spam numbers | /v2/spam-directory | {"country":"US","category":"SCAM","page":1,"limit":20} |
| trends | Insights | /v2/trends | {"country":"ES"} |
| smishing | What is smishing? | /v2/smishing | {"message":"CORREOS: su paquete está retenido. Pague urgente las tasas en https://correos-entrega.info/pago","country":"ES"} |
| link-check | Check a link | /v2/link-check | {"url":"http://192.168.1.1/login","country":"ES"} |
| safety-tools | Safety tools | /v2/safety-tools | {"text":"URGENTE: su cuenta BBVA ha sido bloqueada, verifique en https://bbva-seguro.com/login","mode":"email","country":"ES"} |
| sms-filter | SMS spam filter | /v2/sms-filter | {"country":"ES"} |
| qr-check | Is this QR code safe? | /v2/qr-check | {"payload":"BCD\n002\n1\nSCT\n\nAparcamientos Ejemplo SL\nES9121000418450200051332\nEUR49.90\n\n\nMulta de aparcamiento 4471","country":"ES"} |
| email-headers | Is this email real? | /v2/email-headers | {"headers":"Delivered-To: [email protected]\nReceived: from mail.bank.example (mail.bank.example [192.0.2.10]) by mx.google.com with ESMTPS id x1 for <[email protected]>; Tue, 27 Oct 2026 09:00:00 -0700\nAuthentication-Results: mx.google.com; dkim=pass [email protected] header.s=s1; spf=pass (google.com: domain of [email protected] designates 192.0.2.10 as permitted sender) [email protected]; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=bank.example\nFrom: \"Bank Alerts\" <[email protected]>\nReply-To: [email protected]\nSubject: Your statement is ready\nMessage-ID: <[email protected]>","country":"ES"} |
| mx-lookup | MX record lookup | /v2/mx-lookup | {"domain":"example.com"} |
| spf-check | SPF record checker | /v2/spf-check | {"domain":"example.com"} |
| dmarc-check | DMARC checker | /v2/dmarc-check | {"domain":"example.com"} |
| dkim-check | DKIM checker | /v2/dkim-check | {"domain":"example.com","selector":"s1"} |
| email-verify | Email address checker | /v2/email-verify | {"email":"[email protected]"} |
| website-age | How old is this website? | /v2/website-age | {"url":"https://www.example.com/login","country":"ES"} |
| domain-popularity | Domain popularity check | /v2/domain-popularity | {"url":"https://shop.example.com/cart","country":"ES"} |
| website-legit | Is this website legit? | /v2/website-legit | {"url":"https://[email protected]/login","country":"ES"} |
Available endpoints
Only reviewed or public technical facts are shown. Private identities and protection signals stay hidden.
API v1 · phone is required: a string of up to 64 characters, preferably in E.164 format. country is a supported two-letter country code; it is optional and defaults to ES. Content-Type must be application/json.
| HTTP | URL | Purpose | Requirements |
|---|---|---|---|
| POST | /v2/tools | Use with the API | Authorization: Bearer · Pro |
| GET | /v2/tools | NoCall product catalog | Authorization: Bearer · Pro |
| GET | /v2/openapi.json | OpenAPI 3.1 | — |
| POST | /v2/who-calls | Who is calling me? | Authorization: Bearer · Pro |
| POST | /v2/phone-exposure | Has my number been leaked? | Authorization: Bearer · Pro |
| POST | /v2/phone-intelligence | Phone intelligence | Authorization: Bearer · Pro |
| POST | /v2/phone-risk | Phone risk | Authorization: Bearer · Pro |
| POST | /v2/carrier-lookup | Carrier lookup | Authorization: Bearer · Pro |
| POST | /v2/verified-business | Verified business reverse lookup | Authorization: Bearer · Pro |
| POST | /v2/phone-formats | Phone number formats | Authorization: Bearer · Pro |
| POST | /v2/callback-cost | How much does it cost to call back? | Authorization: Bearer · Pro |
| POST | /v2/prefix-origin | Where is this area code from? | Authorization: Bearer · Pro |
| POST | /v2/number-validator | Phone number validator and formatter | Authorization: Bearer · Pro |
| POST | /v2/line-type | Is it a mobile or a landline? | Authorization: Bearer · Pro |
| POST | /v2/premium-rate | Is it a premium-rate number? | Authorization: Bearer · Pro |
| POST | /v2/wangiri | Wangiri check: is this missed call a scam? | Authorization: Bearer · Pro |
| POST | /v2/commercial-400 | Is this sales call legal? | Authorization: Bearer · Pro |
| POST | /v2/number-research | Research a number with AI | Authorization: Bearer · Pro |
| POST | /v2/dial-code | Asked to dial a code? | Authorization: Bearer · Pro |
| POST | /v2/call-scam-check | Is this call a scam? | Authorization: Bearer · Pro |
| POST | /v2/sms-check | Check if a text message is a scam | Authorization: Bearer · Pro |
| POST | /v2/sms-brand | Is this text from a brand real? | Authorization: Bearer · Pro |
| POST | /v2/sms-sender | Who sent me this text? | Authorization: Bearer · Pro |
| POST | /v2/sms-code | Asked for a code sent by SMS? | Authorization: Bearer · Pro |
| POST | /v2/sms-report | Where to report a scam text | Authorization: Bearer · Pro |
| POST | /v2/sms-campaigns | SMS scam campaigns | Authorization: Bearer · Pro |
| POST | /v2/sms-redact | Remove your data from a text | Authorization: Bearer · Pro |
| POST | /v2/callback-number | Should I call the number in this message? | Authorization: Bearer · Pro |
| POST | /v2/prefix-directory | Prefixes | Authorization: Bearer · Pro |
| POST | /v2/operator-directory | Operators | Authorization: Bearer · Pro |
| POST | /v2/calling-codes | International codes | Authorization: Bearer · Pro |
| POST | /v2/spam-directory | Spam numbers | Authorization: Bearer · Pro |
| POST | /v2/trends | Insights | Authorization: Bearer · Pro |
| POST | /v2/smishing | What is smishing? | Authorization: Bearer · Pro |
| POST | /v2/link-check | Check a link | Authorization: Bearer · Pro |
| POST | /v2/safety-tools | Safety tools | Authorization: Bearer · Pro |
| POST | /v2/sms-filter | SMS spam filter | Authorization: Bearer · Pro |
| POST | /v2/qr-check | Is this QR code safe? | Authorization: Bearer · Pro |
| POST | /v2/email-headers | Is this email real? | Authorization: Bearer · Pro |
| POST | /v2/mx-lookup | MX record lookup | Authorization: Bearer · Pro |
| POST | /v2/spf-check | SPF record checker | Authorization: Bearer · Pro |
| POST | /v2/dmarc-check | DMARC checker | Authorization: Bearer · Pro |
| POST | /v2/dkim-check | DKIM checker | Authorization: Bearer · Pro |
| POST | /v2/email-verify | Email address checker | Authorization: Bearer · Pro |
| POST | /v2/website-age | How old is this website? | Authorization: Bearer · Pro |
| POST | /v2/domain-popularity | Domain popularity check | Authorization: Bearer · Pro |
| POST | /v2/website-legit | Is this website legit? | Authorization: Bearer · Pro |
| GET | /v1/data/account | API key and credits | Authorization: Bearer |
| POST | /v1/data/phone-lookups | Phone intelligence | Authorization: Bearer · Pro |
| POST | /v1/data/phone-risk-checks | Phone risk | Authorization: Bearer · Pro |
| POST | /v1/data/carrier-lookups | Carrier lookup | Authorization: Bearer · Pro |
| POST | /v1/data/reverse-phone-lookups | Verified business reverse lookup | Authorization: Bearer |
| POST | /v1/data/phone-exposure-checks | Has my number been leaked? | Authorization: Bearer · Pro |
| POST | /v1/data/bulk-lookups | Bulk phone lookups | Authorization: Bearer |
| GET | /v1/data/products | NoCall product catalog | — |
| GET | /v1/data/openapi.json | OpenAPI 3.1 | — |
Responses
Invented example, not a real lookup. Do not call or open its links.
data contains the result; meta includes requestId, unitsCharged and usage where applicable. The synthetic excerpt shows the balance after one lookup. A valid not-found result also costs 1 credit; validation and provider errors and reading the balance are free. Missing data does not prove a number is safe. See OpenAPI for complete schemas.
{
"data": {
"tool": "who-calls",
"result": {
"phoneNumber": "+12025550123",
"found": true,
"updatedAt": "2026-10-01T09:30:00.000Z",
"risk": {
"score": 72,
"level": "high"
},
"reportCount": 14,
"categories": [
"TELEMARKETING"
],
"verified": false,
"carrier": null,
"verifiedBusiness": null
}
},
"meta": {
"requestId": "req_example",
"unitsCharged": 1,
"usage": {
"periodStart": "2026-10-01",
"unitLimit": 20,
"unitsUsed": 3,
"unitsRemaining": 17
}
}
}| tool | data.result |
|---|---|
| who-calls | phoneNumber, found, updatedAt, risk, reportCount, categories, verified, carrier, verifiedBusiness |
| phone-exposure | atRisk |
| phone-intelligence | phoneNumber, found, updatedAt, risk, reportCount, categories, verified, carrier, verifiedBusiness, commentCount, aiRiskLevel, prefixRisk |
| phone-risk | phoneNumber, found, updatedAt, risk, signals |
| carrier-lookup | phoneNumber, found, updatedAt, carrier |
| verified-business | phoneNumber, found, updatedAt, verifiedBusiness |
| phone-formats | e164, national, international, callingCode, country, valid |
| callback-cost | tier, scope, callingCode, registry |
| prefix-origin | kind, planLoaded, numberType, foreignCode, national, row, complete, rows, factsType |
| number-validator | valid, possible, country, callingCode, type, e164 |
| line-type | e164, valid, type, lineKind |
| premium-rate | category, callbackRisk, prefix, callingCode, source |
| wangiri | verdict, code, nanpArea, entry |
| commercial-400 | verdict, prefix |
| number-research | answer, sources, countryCode, language, cached |
| dial-code | code, kind, action, service, forwardsTo, calls, risk, undo, operator |
| call-scam-check | verdict, signals, actions, reportChannel |
| sms-check | verdict, confidence, reason |
| sms-brand | verdict, host, brand, officialDomains, sightings |
| sms-sender | kind, tooLong, brand, lookalike, digits, code |
| sms-code | verdict, severity, serviceRecoverySteps, stepCodes |
| sms-report | channel, verified, stepCodes, reportFields |
| sms-campaigns | totalCampaigns, totalSightings, topBrands, topDomains |
| sms-redact | text, counts, total |
| callback-number | numbers, signals, attention |
| prefix-directory | countryCode, callingCode, planVersion, total, page, limit, hasMore, rows |
| operator-directory | operators, specialPrefixes |
| calling-codes | rows, total |
| spam-directory | view, totals, categories, topReported, category, total, page, limit, hasMore, rows |
| trends | totals, activity24h, verification, freshness, categoryDistribution, phoneTypes, topOperators, growthTimeline, topPrefixes, searchTrends, communityDistribution, impersonationRanking, aiBreakdown |
| smishing | verdict, score, attention, signals, hosts, linkFlags, brand, brandSlug |
| link-check | host, hostAscii, official, brand, hosts, linkFlags, signals, attention |
| safety-tools | attention, signals, hosts, linkFlags |
| sms-filter | country, version, updatedAt, source, counts |
| qr-check | payload, signals, attention, hosts, linkFlags, link, numbers |
| email-headers | fromDomain, fromDomainAscii, displayName, replyToDomain, returnPathDomain, senderDomain, subject, auth, authenticated, brand, official, freeMail, signals, attention |
| mx-lookup | domain, domainAscii, found, records, nullMx, implicitMx, acceptsMail, provider, signals, attention |
| spf-check | domain, domainAscii, found, record, recordCount, terms, allResult, lookups, includes, signals, valid, attention |
| dmarc-check | domain, domainAscii, found, record, foundAt, inherited, policy, subdomainPolicy, effectivePolicy, percentage, alignment, reports, signals, valid, attention |
| dkim-check | domain, domainAscii, selectorGiven, selectorsTried, keys, signals, attention |
| email-verify | domain, domainAscii, status, syntaxValid, acceptsMail, mx, disposable, role, freeMail, suggestion, signals, attention |
| website-age | domain, domainAscii, rdapAvailable, found, registeredDomain, registered, updated, expires, ageDays, registrar, status, campaigns, signals, attention |
| domain-popularity | domain, domainAscii, ranked, rank, rankedDomain, refSubnets, refIps, listSize, updated, source |
| website-legit | domain, domainAscii, verdict, official, brand, ageDays, registered, ranked, rank, campaigns, signals, linkFlags, attention, checks |
Credits and limits
Pro gives you 20 free credits every month
Each API call costs 1 credit. Monthly credits are used first.
Regenerating disables your previous keys. Your credit balance stays the same.
curl 'https://api.nocall.io/v1/data/account' \
--header "Authorization: Bearer $NOCALL_API_KEY"Retries and bulk lookups
Generate a fresh Idempotency-Key for each new operation. Keep that key only to retry the same operation with the same input.
Idempotency-Key is optional for single lookups and required for bulk: 8–128 characters (letters, digits, dots, hyphens, underscores or colons). When retrying, keep the same key, path, API key and body. A replay is not charged again. Check the balance before retrying an ambiguous response.
A batch accepts up to 50 inputs. product selects one of the operations listed in the example. There must be enough credits for all valid inputs before starting; only completed valid results are charged. Concurrent requests share the balance: if it runs out before the final debit, the request returns 429 without charging it.
8–128 ASCII: A–Z a–z 0–9 . _ : -
TTL: 24 hphone-lookup
phone-risk
carrier-lookup
reverse-phone-lookup
phone-exposureREQUEST_ID="$(uuidgen)" && [ -n "$REQUEST_ID" ] &&
curl --request POST 'https://api.nocall.io/v1/data/bulk-lookups' \
--header "Authorization: Bearer $NOCALL_API_KEY" \
--header 'Content-Type: application/json' \
--header "Idempotency-Key: $REQUEST_ID" \
--data '{"product":"phone-risk","inputs":[{"phone":"+12025550123","country":"US"}]}'Troubleshooting
| HTTP | Interpret the result |
|---|---|
| 401 | The key is missing, Bearer format is incorrect, or the key is expired or revoked. Check the header or generate a new key in your account. |
| 403 | You need credits: the 20 a month included with an active Pro account, or credits bought on your account page. An account with neither receives 403 pro_required. |
| 400 / 422 | Check the JSON, phone, country and Idempotency-Key. Validation errors do not consume credits. |
| 409 | The idempotency key was used with another body, or the request is still processing. To retry the same operation, keep its body and wait. |
| 429 | Credits are exhausted or the request-rate limit was reached. Check /account and X-RateLimit-Remaining. Honor Retry-After when present. ai_busy means the AI is busy: the request is not charged; retry after Retry-After. |
| 500 / 503 | The service or provider is unavailable, or the beta is disabled. Wait and retry with the same Idempotency-Key; avoid immediate retry loops. tool_warming means the tool is still starting: the request is not charged; retry after Retry-After. |
