Zelnum

API Documentation

Integrate realtime and bulk phone or email detection in minutes

Base URL https://api.zelnum.com/api/v1
OpenAPI 3.1 YAML

Authentication

All authenticated endpoints require credentials. Use X-API-Key (recommended) or an Authorization: Bearer header; the public product catalog is unauthenticated.

http
X-API-Key: YOUR_KEY_HERE

Authorization: Bearer YOUR_KEY_HERE

Your key is 51 characters long: the prefix zn_ followed by 48 random characters. Keys issued earlier with the ck_ prefix remain fully supported.

Your API key is available in the Console under "API Center". The plaintext key is shown only once when created. Save it immediately.

Response Format

All endpoints return JSON.

Realtime response example

json
{
  "request_id": "8c1e4f91-7bd8-4d7e-a3ae-3d7e5b0c6c11",
  "status": "succeeded",
  "replayed": false,
  "results": []
}

Bulk response example

json
{
  "mode": "async",
  "task_id": "xKj9aP3qLm7v",
  "message": "Task queued."
}
GET /v1/balance

Get Balance

Returns the current USD balance for the authenticated account.

Response Example

json
{ "balance": "5.230000" }
GET /v1/products

Product List

Public product catalog; no API key is required. It returns active realtime and bulk products, their series, and minimum quantities. Read it before submitting.

Response Example

json
{
  "data": [
    {
      "id": 101,
      "slug": "whatsapp-realtime",
      "name": "WhatsApp Number Checker",
      "name_translations": { "zh_CN": "WhatsApp 注册检测" },
      "mode": "realtime",
      "series": "phone",
      "min_phones": 1
    }
  ]
}
GET /v1/api-key

API Key Details

Returns metadata for the authenticated account's API key. The plaintext key is never returned.

json
{
  "api_key_id": 42,
  "masked_key": "ck_••••••••••••••••••••••••••••••••••••••••••••••••",
  "last_used": "2026-09-05T10:00:00Z",
  "created_at": "2026-08-01T09:00:00Z"
}
The plaintext key is shown only once when created or rotated; this endpoint returns only a masked value.

Error Codes

On failure, check the HTTP status code and message field.

Error Body

json
{
  "code": "insufficient_balance",
  "message": "Insufficient balance for this submission."
}
Business errors always return a machine-readable code you can branch on programmatically. Malformed request parameters (validation) and unknown routes return the standard Laravel shape instead: { "message": "...", "errors": { ... } }. Validate inputs before submitting to avoid it.

Error

code HTTP Description
unauthorized 401 API key missing, invalid, or inactive.
account_banned 403 Account suspended. Contact support.
invalid_realtime_request 400 Malformed realtime request (e.g. a phone number without a + international prefix while country is omitted).
idempotency_key_required 400 Realtime requests require the Idempotency-Key header.
invalid_idempotency_key 422 Idempotency-Key must be 1-128 characters from letters, digits and . _ : -
idempotency_conflict 409 The same Idempotency-Key was used with a different request payload.
request_in_progress 409 An identical realtime request is still being processed. Retry shortly (Retry-After: 1).
empty_input 422 The uploaded file contains no usable rows.
product_not_found 422 The submitted product slug does not exist or is inactive.
product_mode_not_supported 422 This endpoint does not accept this product mode (realtime products cannot be used on bulk endpoints).
invalid_country 422 The product does not support the submitted country.
too_few_numbers 422 The submission is below the product minimum.
too_many_numbers 422 The submission exceeds the platform maximum.
insufficient_balance 402 Not enough balance to cover this submission. Top up and retry.
realtime_disabled 403 Realtime detection is not enabled for this account.
realtime_rate_limited 429 Realtime rate limit exceeded. Respect retry_after.
product_pricing_unavailable 503 Pricing for this product is not configured yet. Contact support.
detection_capacity_unavailable 503 No detection capacity available right now. Retry later.
realtime_route_unavailable 503 No realtime route available. Retry later.
realtime_fact_cache_unavailable 503 A realtime dependency is temporarily unavailable. Retry later.
realtime_rate_limiter_unavailable 503 The rate limiter is temporarily unavailable. Retry later.
not_found 404 task_id does not exist or belongs to another account.
result_not_ready 422 The task is not complete or its result file has not been generated.
result_expired 404 The result file is expired, missing, or unavailable.
validation_failed 422 Check required fields, number format, and file type.
internal_error 500 Unexpected server error. Safe to retry with the same Idempotency-Key.

Rate Limits

API requests are rate limited per API key, per endpoint group:

Endpoints Limit
GET /v1/products · GET /v1/balance · GET /v1/api-key · GET /v1/tasks/{token} · GET /v1/tasks/{token}/result · GET /v1/tasks/{token}/download 60 requests / minute per API key (120 / minute per IP)
POST /v1/detect · POST /v1/detect/file · POST /v1/quotes/bulk 10 requests / minute per API key (30 / minute per IP)
POST /v1/realtime/quote/{series} · POST /v1/realtime/check/{series} · POST /v1/realtime/detect Token bucket per API key: burst 60, refill 1/s (≈60 / minute sustained); per account: burst 120, refill 2/s. The IP layer allows 180 / minute. Every response carries an X-RateLimit-Remaining header.

When a limit is exceeded the API returns 429 with a Retry-After header (realtime responses also include a retry_after field). Stop sending requests for the indicated number of seconds, then resume with exponential backoff.

Single (real-time)

Synchronously check one phone number or email address. A request may select multiple realtime products from one series; use realtime product IDs, never batch product slugs.

POST /v1/realtime/check/{series}

Realtime Single Check

Synchronously check one phone number or email address. A request may select multiple realtime products from one series; use realtime product IDs, never batch product slugs.

Idempotency-Key is required. Retrying the same request with the same key does not charge twice; changing the payload returns 409. Reused results have cached=true; failed or unknown results are not cached as facts.

Parameters

Field Type Required Description
series path Yes Series: phone or email; must match the selected realtime product series.
identifier string Yes One identifier: an E.164 phone number (for example +8613800138000) or a valid email address.
country string No Phone only: optional for a complete E.164 number; a national number requires a matching ISO country code. Leave empty for email.
product_ids array<int> Yes An array of 1 to 10 realtime product IDs.

Response Example

json
{
  "request_id": "8c1e4f91-7bd8-4d7e-a3ae-3d7e5b0c6c11",
  "identifier": "+8613800138000",
  "series": "phone",
  "status": "succeeded",
  "request_status": "completed",
  "total_reserved": 0.004000,
  "total_charged": 0.004000,
  "total_refunded": 0.000000,
  "charged_amount": 0.004000,
  "refunded_amount": 0.000000,
  "replayed": false,
  "results": [
    {
      "product_id": 101,
      "product": "whatsapp-realtime",
      "result": "valid",
      "cached": false,
      "billing_status": "charged",
      "charged_amount": 0.004000,
      "refunded_amount": 0.000000,
      "checked_at": "2026-09-05T10:00:00Z",
      "error_code": null
    }
  ]
}

cURL Example

bash
curl -X POST "https://api.zelnum.com/api/v1/realtime/check/phone" \
  -H "X-API-Key: YOUR_KEY_HERE" \
  -H "Idempotency-Key: UNIQUE_REQUEST_ID" \
  -H "Content-Type: application/json" \
  -d '{"identifier":"+8613800138000","country":"CN","product_ids":[101,102]}'
bash
curl -X POST "https://api.zelnum.com/api/v1/realtime/check/email" \
  -H "X-API-Key: YOUR_KEY_HERE" \
  -H "Idempotency-Key: UNIQUE_REQUEST_ID" \
  -H "Content-Type: application/json" \
  -d '{"identifier":"[email protected]","country":null,"product_ids":[201]}'

Billing: each product uses its snapshotted per-check price, including cache hits. Only valid and invalid results are charged; unknown, timeout and busy items are refunded. total_reserved = total_charged + total_refunded; charged_amount is the net charge.

A partially successful combo returns HTTP 200 with status=partial_succeeded; all failed returns status=failed. Inspect each billing_status and error_code instead of relying on HTTP 200 alone.

Idempotency-Key is limited to 191 bytes and scoped to the user. After a timeout or HTTP 500, retry the original content with the original key. In-flight replays return 409/request_in_progress. Logs and replay results are retained for 30 days by default.

HTTPcodeMeaning / action
400invalid_realtime_request / idempotency_key_requiredFix the number, products or request key; no prepayment.
401 / 403unauthorized / account_banned / realtime_disabledCheck the key, account status and realtime access; no prepayment.
402insufficient_balanceInsufficient balance; no combo item starts.
409request_in_progress / idempotency_conflictRetry an in-flight request after Retry-After; a conflicting payload cannot reuse the key.
429realtime_rate_limitedWait for Retry-After; no prepayment.
503realtime_route_unavailable / realtime_fact_cache_unavailable / realtime_rate_limiter_unavailableThe route, cache or limiter is unavailable; no prepayment. Retry later.
500internal_errorThe outcome is uncertain. Retry with the original key; do not blindly submit a new key.

Item error_code values identify provider, channel-capacity, deadline, cache or concurrency-protection failures. Failed items are not charged.

The compatibility endpoint POST /v1/realtime/detect is temporarily retained for older clients. New integrations should use /v1/realtime/check/phone or /v1/realtime/check/email.

Product List · Single (real-time)

Realtime products are selected by product ID and series; do not use bulk product slugs.

Product name Series Identifier Minimum
Amazon Number Checker phone #53 1
Amazon Email Checker email #54 1
Apple ID Number Checker phone #57 1
Apple ID Email Checker email #58 1
BAND Number Checker phone #60 1
Facebook Number Checker phone #51 1
Facebook Email Checker email #52 1
Instagram Number Checker phone #48 1
Instagram Email Checker email #49 1
Microsoft Number Checker phone #59 1
Telegram Number Checker phone #50 1
Viber Number Checker phone #55 1
WhatsApp Number Checker phone #47 1
X Phone Number Checker phone #61 1

Bulk (async)

Submit a phone or email array for asynchronous bulk detection. Cost is pre-deducted and unchecked items are refunded after completion.

POST /v1/detect

Submit Detection (Array)

Submit a phone or email array for asynchronous bulk detection. Cost is pre-deducted and unchecked items are refunded after completion.

The submission must meet the selected product minimum and stay below the platform maximum (2,000,000 by default). Email products omit country; phone products require it.

HTTP 202 Accepted

Parameters

Field Type Required Description
product string Yes Product slug. See the product list.
country string Required for phone; omit for email Required ISO 3166-1 alpha-2 country code for phone products; omit for email products.
phones array Yes Array of phones or emails; the product defines the minimum and the platform maximum is 2,000,000 by default.

Response Example

json
{
  "mode": "async",
  "task_id": "xKj9aP3qLm7v",
  "idempotent_replay": false,
  "message": "Task queued. Poll GET /api/v1/tasks/xKj9aP3qLm7v for progress.",
  "recovery_pending": false,
  "summary": {
    "total": 5000,
    "cost_deducted": 0.500000
  }
}
POST /v1/detect/file

Submit Detection (File Upload)

Upload a TXT or CSV file for bulk detection, one phone or email per line, max 50 MB.

HTTP 202 Accepted

Parameters

Content-Type: multipart/form-data

Field Type Required Description
product string Yes Product slug
country string Required for phone; omit for email ISO country code for phone products; omit for email products.
file file Yes TXT or CSV file, one phone or email per line, max 50 MB.

Response Example

json
{
  "mode": "async",
  "task_id": "qH5rZ7Lp3Wm9",
  "idempotent_replay": false,
  "message": "File queued (10000 numbers). Poll GET /api/v1/tasks/qH5rZ7Lp3Wm9 for progress.",
  "recovery_pending": false,
  "summary": {
    "total": 10000,
    "cost_deducted": 1.000000
  }
}
GET /v1/tasks/{token}

Get Task Status

Poll the task until status is completed or failed. Recommended interval: 3–5 seconds.

Response Example

json
{
  "task_id": "xKj9aP3qLm7v",
  "status": "completed",
  "progress": 100,
  "product": "YOUR_PRODUCT_SLUG",
  "country": "CN",
  "submitted": 5000,
  "prefiltered": 0,
  "deduped": 0,
  "total": 5000,
  "processed": 5000,
  "valid": 3800,
  "invalid": 1200,
  "unknown": 0,
  "unknown_processed": 0,
  "unknown_unprocessed": 0,
  "stage": "completed",
  "stage_seconds": 12,
  "last_progress_at": "2026-09-05T10:00:12+00:00",
  "failure_message": null,
  "cost_deducted": "0.500000",
  "cost_refunded": "0.000000",
  "result_available": true,
  "result_expires_at": "2026-05-02T10:00:00+00:00",
  "created_at": "2026-05-01T10:00:00+00:00"
}

Task Status

status Description
pending Queued and waiting for resources.
processing Detection is in progress.
completed Completed. The result is ready to download.
failed Execution failed.
GET /v1/tasks/{token}/result

Get Download URL

Once completed, retrieve a download URL for the result file. Files are retained for 7 days by default (controlled by the result_retention_days system setting).

Response Example

json
{
  "task_id": "xKj9aP3qLm7v",
  "download_url": "https://api.zelnum.com/api/v1/tasks/xKj9aP3qLm7v/download",
  "expires_at": "2026-05-02T10:00:00+00:00",
  "summary": {
    "submitted": 5000,
    "prefiltered": 0,
    "deduped": 0,
    "total": 5000,
    "valid": 3800,
    "invalid": 1200,
    "unknown": 0,
    "unknown_processed": 0,
    "unknown_unprocessed": 0
  }
}
GET /v1/tasks/{token}/download

Download Result

Downloads the result file for a completed task while it is still within the retention period.

Response Example

Content-Type: application/zip (or text/csv for a single result).

This endpoint streams a file instead of JSON. It returns 404/422 when the task is not ready, expired, unavailable, or belongs to another account.

Product List · Bulk (async)

Use the slug value in the product field when submitting a task.

Product name Identifier Minimum
Amazon Number Checker amazonValid 500
Amazon Email Checker amazonEmailValid 1000
Apple ID Number Checker appleidValid 2000
Apple ID Email Checker appleidEmailValid 1000
BAND Number Checker bandValid 500
Binance Number Checker binanceValid 2000
Binance Email Checker binanceEmailValid 2000
CoinW Number Checker coinwValid 2000
CoinW Email Checker coinwEmailValid 2000
Facebook Number Checker fbValid 500
Facebook Email Checker fbEmailValid 1000
HTX Number Checker htxValid 1000
HTX Email Checker htxEmailValid 2000
iMessage Number Checker imessageValid 2000
Instagram Number Checker insValid 500
Instagram Email Checker insEmailValid 1000
KuCoin Number Checker kucoinValid 1000
KuCoin Email Checker kucoinEmailValid 2000
LINE Age & Gender lineGender 2000
LINE Number Checker lineValid 2000
Linkedin Full Profile linkedinGender 2000
Linkedin Number Checker linkedinValid 2000
Microsoft Number Checker microsoftValid 500
RCS Support Check rcsValid 1000
Signal Number Checker signalValid 2000
Snapchat Number Checker snapchatValid 500
Telegram Full Profile tgGender 500
Telegram Number Checker tgValid 1000
Telegram Activity Check tgActive 500
TikTok Username Lookup tiktokUsername 2000
Viber Number Checker viberValid 1000
Viber Activity Check viberActive 1000
WhatsApp Full Profile waGender 1000
WhatsApp Number Checker waValid 1000
WhatsApp Activity Details waActive 500
X Phone Number Checker twitterValid 2000
X Email Checker twitterEmailValid 2000
Zalo Age & Gender zaloGender 500
Zalo Number Checker zaloValid 2000
Internet Activity Filter live-activity-filter 2000
Phone Status Check phone-status-check 2000
Phone On/Off Check phone-onoff-check 1500
Phone Model Detection phone-model-detection 500
HLR Lookup hlr-lookup 2000

Full Examples

Copy and run these cURL examples — replace YOUR_KEY_HERE and parameters.

1. Get balance

bash
curl -X GET "https://api.zelnum.com/api/v1/balance" \
  -H "X-API-Key: YOUR_KEY_HERE"

2. Submit detection

bash
curl -X POST "https://api.zelnum.com/api/v1/detect" \
  -H "X-API-Key: YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "product": "YOUR_PRODUCT_SLUG",
    "country": "CN",
    "phones": ["+8613800138000", "+8613900139000"]
  }'

3. Upload file

bash
curl -X POST "https://api.zelnum.com/api/v1/detect/file" \
  -H "X-API-Key: YOUR_KEY_HERE" \
  -F "product=YOUR_PRODUCT_SLUG" \
  -F "country=CN" \
  -F "file=@/path/to/numbers.txt"

4. Poll task status

bash
curl -X GET "https://api.zelnum.com/api/v1/tasks/xKj9aP3qLm7v" \
  -H "X-API-Key: YOUR_KEY_HERE"

5. Get download URL

bash
curl -X GET "https://api.zelnum.com/api/v1/tasks/xKj9aP3qLm7v/result" \
  -H "X-API-Key: YOUR_KEY_HERE"
© 2026 Zelnum · Console