Skip to content

API documentation API v1

Check one phone number or e-mail in real time, or submit a list as a bulk job and download one result file. Every request uses a Bearer API key.

Authentication

Create a key on the API keys page, then replace the placeholder below in your own terminal. The examples are only text; copying them sends nothing.

API originhttps://api.numdetect.com
Set your key locally
# API origin: https://api.numdetect.com
export NUMDETECT_API_KEY='YOUR_API_KEY'
  • Send Authorization: Bearer <key> with every request. JSON requests also need Content-Type: application/json. No cookies, CSRF header or Origin header are needed.
  • A key can read products, run single and bulk checks, read their results and read your balance history. Account settings, keys and top-ups are managed only in the signed-in dashboard.
  • You can create up to 10 keys, for example one per system, and delete any of them at once.

Keep keys in your server environment. Do not put keys in URLs, screenshots, shared logs or committed source files.

Products

Read the current catalog before choosing product IDs. The response lists every product on sale with its input type, prices, bulk minimum and supported countries.

List products
curl --fail-with-body --silent --show-error -X GET "https://api.numdetect.com/api/v1/products" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY"

single and bulk tell whether the product is available for that kind of check right now. countries is ["*"] for every country, a list of country codes, or empty for e-mail products. Prices are USD micros per check.

Single check

POST /api/v1/checks takes one phone number or one e-mail address and a list of product IDs. The request waits until every product has answered (up to about 45 seconds) and returns the finished check.

Check a phone number
curl --fail-with-body --silent --show-error -X POST "https://api.numdetect.com/api/v1/checks" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"phone":"+12025550147","products":["whatsapp","telegram"]}'
Check an e-mail address
curl --fail-with-body --silent --show-error -X POST "https://api.numdetect.com/api/v1/checks" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"email":"[email protected]","products":["apple_email","spotify_email"]}'

Write phone numbers with their + country code. For a number without one, add "country": "GB" (an ISO country code) to the request.

200 · Check

The response is the check: id, the normalized input, its country, charged and one entry in results per product. Each result has status, result (true or false when status is success) and info for extra fields some products return.

success

A definite answer: result is true (registered) or false (not registered). Only these are charged.

unknown

The product could not tell. result is null and nothing is charged; never read it as false.

failed

The product could not be reached. result is null and nothing is charged; you can check again later.

Read one check
curl --fail-with-body --silent --show-error -X GET "https://api.numdetect.com/api/v1/checks/$CHECK_ID" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY"
List recent checks
curl --fail-with-body --silent --show-error -X GET "https://api.numdetect.com/api/v1/checks?limit=20" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY"

Bulk check

POST /api/v1/bulk-jobs uploads a file as multipart form data. The file is split into one list per country, and each country is checked by each product you choose.

Submit a bulk job
curl --fail-with-body --silent --show-error -X POST "https://api.numdetect.com/api/v1/bulk-jobs" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "[email protected]" \
  -F "products=whatsapp,telegram" \
  -F "input_kind=phone" \
  -F "max_cost=50000000" \
  -F "column=0" \
  -F "header=true"
  • file: UTF-8 CSV or plain text, up to 100 MB and 1,000,000 rows. Other columns are kept and returned in the result file.
  • input_kind is phone or email. column is the 0-based column with the numbers (default 0); header=true skips the first row.
  • country (optional) is used for phone numbers written without a country code. Numbers starting with + or 00 keep their own country.
  • max_cost is the most you accept to pay, in USD micros. The job is refused, and nothing is charged, if its cost would be higher or your balance is too low.
200 · BulkJob

The response is the job with status running, its row counts (total, valid, duplicate, invalid), the amount held and one task per country and product. Keep id as your JOB_ID.

Bulk status and results

Read the job until status is completed, failed or cancelled. Large lists can take a while, so poll every minute or two, or use a webhook.

Read a bulk job
curl --fail-with-body --silent --show-error -X GET "https://api.numdetect.com/api/v1/bulk-jobs/$JOB_ID" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY"
List recent bulk jobs
curl --fail-with-body --silent --show-error -X GET "https://api.numdetect.com/api/v1/bulk-jobs?limit=20" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY"

Download the result file

When result_ready is true, GET /result returns a download link valid for 10 minutes. The link itself needs no key. Ask for a new link whenever you need to download again.

Get the link, then download
url=$(curl --fail-with-body --silent --show-error -X GET "https://api.numdetect.com/api/v1/bulk-jobs/$JOB_ID/result" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY" | jq -r .url)
curl --fail --silent --show-error --output result.csv "$url"

result.csv keeps every original row in its original order and adds numdetect_status (valid, duplicate or invalid), numdetect_country and one column per product with yes, no, unknown, unsupported, failed or cancelled.

Cancel a running job

Countries that have not been checked yet stop, and their held amount returns to your balance.

Cancel a bulk job
curl --fail-with-body --silent --show-error -X POST "https://api.numdetect.com/api/v1/bulk-jobs/$JOB_ID/cancel" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY"

Webhooks

Set a webhook URL on the account settings page to be told when a bulk job finishes. We send one HTTPS POST per finished job:

Request body
{
  "type": "bulk_job.finished",
  "data": {
    "id": "10000000-0000-4000-8000-000000000003",
    "status": "completed",
    "total_rows": 1000,
    "valid_rows": 982,
    "charged": 245500,
    "completed_at": "2026-11-11T08:30:00Z"
  }
}

Each request carries webhook-id, webhook-timestamp and webhook-signature headers. The signature is v1, followed by the Base64 HMAC-SHA256 of "<webhook-id>.<webhook-timestamp>.<body>", using your signing secret (whsec_…, Base64 after the prefix). Compare it before trusting the body.

Answer with any 2xx status. Failed deliveries are retried a few times, a few minutes apart. Treat webhook-id as unique, since a retried delivery can arrive twice.

Fees and balance

A single check is charged its price for each product with a definite answer. Unknown and failed answers are free.

A bulk job holds its cost when you submit it: for each country and product, max(valid numbers, the product's bulk minimum) × the bulk price. A completed list is charged in full, unknown rows included. A list that fails or is cancelled is returned to your balance. Duplicate and invalid rows, and countries a product does not support, are free.

Amounts are integer USD micros: 1 USD = 1,000,000 micros.

Read balance history
curl --fail-with-body --silent --show-error -X GET "https://api.numdetect.com/api/v1/balance-logs?limit=20" \
  -H "Authorization: Bearer $NUMDETECT_API_KEY"

POST /checks and POST /bulk-jobs need an Idempotency-Key header (up to 128 characters). Use a new key for each new request. If a response is lost, send the same request again with the same key: you get the first result instead of a second charge.

Price list

Errors

Errors use {error: {code, message, request_id}}. Match the stable code rather than the message, and include request_id when you contact support.

Common API errors
HTTPCodeWhat to do
400invalid_requestCheck the fields, the JSON or form syntax and the input format.
401unauthorizedCheck that the key is present and has not been deleted.
403forbiddenThis action is only available in the signed-in dashboard, or the account is disabled.
404not_foundCheck the ID; only your own checks and jobs can be read.
409conflictThe Idempotency-Key was already used for a different request. Use a new key for a new request.
409insufficient_balance / max_cost_exceededTop up your balance, or raise max_cost if you accept the higher cost.
409product_not_supportedRead the product catalog: the product is off sale or does not take this input.
429rate_limitedSlow down and try again shortly.
503unavailable / dependency_unavailableChecks are temporarily unavailable. Try again later; nothing was charged.
Back to authentication