API Documentation
Integrate realtime and bulk phone or email detection in minutes
Authentication
All authenticated endpoints require credentials. Use X-API-Key (recommended) or an Authorization: Bearer header; the public product catalog is unauthenticated.
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
{
"request_id": "8c1e4f91-7bd8-4d7e-a3ae-3d7e5b0c6c11",
"status": "succeeded",
"replayed": false,
"results": []
}
Bulk response example
{
"mode": "async",
"task_id": "xKj9aP3qLm7v",
"message": "Task queued."
}
/v1/balance
Get Balance
Returns the current USD balance for the authenticated account.
Response Example
{ "balance": "5.230000" }
/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
{
"data": [
{
"id": 101,
"slug": "whatsapp-realtime",
"name": "WhatsApp Number Checker",
"name_translations": { "zh_CN": "WhatsApp 注册检测" },
"mode": "realtime",
"series": "phone",
"min_phones": 1
}
]
}
/v1/api-key
API Key Details
Returns metadata for the authenticated account's API key. The plaintext key is never returned.
{
"api_key_id": 42,
"masked_key": "ck_••••••••••••••••••••••••••••••••••••••••••••••••",
"last_used": "2026-09-05T10:00:00Z",
"created_at": "2026-08-01T09:00:00Z"
}
Error Codes
On failure, check the HTTP status code and message field.
Error Body
{
"code": "insufficient_balance",
"message": "Insufficient balance for this submission."
}
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.
/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.
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
{
"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
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]}'
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.
| HTTP | code | Meaning / action |
|---|---|---|
| 400 | invalid_realtime_request / idempotency_key_required | Fix the number, products or request key; no prepayment. |
| 401 / 403 | unauthorized / account_banned / realtime_disabled | Check the key, account status and realtime access; no prepayment. |
| 402 | insufficient_balance | Insufficient balance; no combo item starts. |
| 409 | request_in_progress / idempotency_conflict | Retry an in-flight request after Retry-After; a conflicting payload cannot reuse the key. |
| 429 | realtime_rate_limited | Wait for Retry-After; no prepayment. |
| 503 | realtime_route_unavailable / realtime_fact_cache_unavailable / realtime_rate_limiter_unavailable | The route, cache or limiter is unavailable; no prepayment. Retry later. |
| 500 | internal_error | The 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.
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.
/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.
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
{
"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
}
}
/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
{
"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
}
}
/v1/tasks/{token}
Get Task Status
Poll the task until status is completed or failed. Recommended interval: 3–5 seconds.
Response Example
{
"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. |
/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
{
"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
}
}
/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).
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
curl -X GET "https://api.zelnum.com/api/v1/balance" \
-H "X-API-Key: YOUR_KEY_HERE"
2. Submit detection
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
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
curl -X GET "https://api.zelnum.com/api/v1/tasks/xKj9aP3qLm7v" \
-H "X-API-Key: YOUR_KEY_HERE"
5. Get download URL
curl -X GET "https://api.zelnum.com/api/v1/tasks/xKj9aP3qLm7v/result" \
-H "X-API-Key: YOUR_KEY_HERE"