API reference
Interactive reference for every MobileValidate API endpoint, generated from the OpenAPI document. Send test requests with the public sandbox key.
Test requests are live. They go straight to the API with the public sandbox key filled in. It answers the documented test numbers and addresses only and is never billed. Swap in your own key under Authentication to try anything else.
Loading the interactive reference…
All operations
Lookups
Real-time checks for up to 100 numbers and e-mail addresses per request.
POST/v1/lookup
Check up to 100 numbers and e-mail addresses
Runs every requested check (see GET /v1/services) for every identifier of the check's input type: phone checks for numbers, e-mail checks for emails. Result rows come back in order: numbers first, then e-mails. The call waits up to wait seconds (default 10) for all answers; if some are still running it answers 202 with status: pending and a next.poll_url (or use a webhook). Checks without real-time support are refused with 403 service_disabled (param checks[i]) — send them in a bulk job. E-mail checks answer only whether an account or mailbox exists — never names, photos or profiles.
| Parameter | In | Description |
|---|---|---|
Idempotency-Key | header | Any unique string (1–255 printable ASCII) for safe retries: a retry with the same key and body within 24 hours returns the stored response (header Idempotent-Replayed: true) instead of running the request again. |
curl https://api.mobilevalidate.com/v1/lookup \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"numbers":["+447700900001"],"checks":["whatsapp","carrier"]}'Responses: 200 All checks completed. · 202 Some checks are still running; poll `next.poll_url` (the Location header) or wait for lookup.completed. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
GET/v1/lookups/{id}
Get a lookup
Returns a lookup created by POST /v1/lookup, optionally waiting up to wait seconds for pending checks. input is masked on later reads; e164 and email are returned. Lookups expire after the account's retention period (404 not_found afterwards).
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
wait | query | Seconds (0–30) to wait for pending checks before answering. |
Responses: 200 The lookup (completed or still pending). · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
Bulk jobs
Bulk checks for up to 50,000 numbers and e-mail addresses per job, with paginated results and downloads.
POST/v1/jobs/estimate
Estimate a bulk job for free
Validates and counts a list without storing it, calling a data source or charging: valid, invalid and duplicate rows, cached answers, and the maximum possible cost (max_cost). Same body as POST /v1/jobs.
curl https://api.mobilevalidate.com/v1/jobs/estimate \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"numbers":["+447700900001","+447700900002","12"],"checks":["whatsapp"]}'Responses: 200 The estimate. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
POST/v1/jobs
Create a bulk job
Checks up to 50,000 numbers and e-mail addresses (JSON body, or a CSV upload as multipart/form-data). The maximum possible cost is reserved up front; cached, inconclusive, invalid and duplicate rows are released when the job finishes. Poll GET /v1/jobs/{id} (or subscribe to job.completed), then page through GET /v1/jobs/{id}/results or download the whole file. Test-key jobs complete immediately.
| Parameter | In | Description |
|---|---|---|
Idempotency-Key | header | Any unique string (1–255 printable ASCII) for safe retries: a retry with the same key and body within 24 hours returns the stored response (header Idempotent-Replayed: true) instead of running the request again. |
curl https://api.mobilevalidate.com/v1/jobs \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"numbers":["+447700900001","+447700900002"],"emails":["[email protected]"],"checks":["whatsapp","email"]}'Responses: 201 Job created. `estimate` shows how the list was counted. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
GET/v1/jobs/{id}
Get a job
Status, progress and cost of a job. wait (0–30 s) holds the request until the job reaches a final status (completed, failed or cancelled) or the time runs out. Keys with jobs:read see their own jobs; jobs:read_all sees every job of the account.
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
wait | query | Seconds (0–30) to wait for pending checks before answering. |
Responses: 200 The job. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
DELETE/v1/jobs/{id}
Cancel a running job or delete a finished job's results
Running job → cancelled: rows not yet sent to a data source are released and never charged; rows already sent finish and are billed as usual. Finished job → its per-row results are deleted now instead of at the end of the retention period (purged_at is set).
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
Responses: 200 The job after cancelling or deleting results. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
GET/v1/jobs/{id}/results
List a job's results
One item per row (number or e-mail address) in input order, with every check of the row. Filter by registered / status of one service; page with limit and after = the previous page's next_cursor.
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
registered | query | Only rows whose answer for `service` is true / false / null. |
status | query | Only rows whose `service` check has this status. |
service | query | Service (code or alias) the registered/status filters apply to; default = the job's first check. With a filter, only rows of that service's input type are returned. |
limit | query | Rows (numbers and e-mails) per page. A row's checks are never split across pages. |
after | query | Cursor from the previous page (`next_cursor`). |
Responses: 200 A page of result items. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
GET/v1/jobs/{id}/download
Download a job's results as CSV or NDJSON
Streams the whole result file, one line per row (numbers, then e-mails) in input order. CSV columns: row_no, input_masked, e164, country, number_status, service, status, registered, business, checked_at, cached, billed (for the row's primary check = first requested check of its kind), then kind, email, email_status, then per service <service>.status, <service>.registered, <service>.<attribute>, <service>.billed (empty for rows of the other kind). NDJSON lines have the same shape as result items.
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
formatrequired | query | File format. |
Responses: 200 The result file (Content-Disposition attachment). · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
Account
Balance, limits and usage of the key's account.
GET/v1/account
Get the account balance
Balance, reserved amount and today's usage (UTC) of the key's account. Needs account:read.
curl https://api.mobilevalidate.com/v1/account \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"Responses: 200 The account. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
GET/v1/limits
Get limits and remaining allowances
Request rate, request sizes, the daily identifiers cap and the key's daily spend cap. Daily counters reset at 00:00 UTC.
curl https://api.mobilevalidate.com/v1/limits \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"Responses: 200 Current limits. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
GET/v1/usage
Get usage by day or by check
Checks, conclusive answers, cached answers, billed units and cost for an inclusive UTC date range (at most 366 days), for the key's mode (live or test). Rows past the retention period are no longer counted.
| Parameter | In | Description |
|---|---|---|
fromrequired | query | First day (UTC). |
torequired | query | Last day (UTC), inclusive. |
group_by | query | One row per day or per check. |
curl https://api.mobilevalidate.com/v1/usage \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"Responses: 200 Usage rows. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
Webhooks
Signed notifications (Standard Webhooks) when lookups and jobs finish. See the webhooks section for the event payloads and https://mobilevalidate.com/docs/webhooks for signature verification.
GET/v1/webhook_endpoints
List webhook endpoints
Every endpoint of the account that is not deleted and has the same mode as the key (test keys list test endpoints, live keys live endpoints). Needs webhooks:manage.
curl https://api.mobilevalidate.com/v1/webhook_endpoints \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"Responses: 200 Endpoints. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
POST/v1/webhook_endpoints
Create a webhook endpoint
Registers a public HTTPS URL (at most 20 per account). The response contains the signing secret — shown only once. The endpoint stays pending_verification until it answers our signed webhook.verification event with a 2xx status. Not available with the public sandbox key.
curl https://api.mobilevalidate.com/v1/webhook_endpoints \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com/hooks/mobilevalidate","events":["lookup.completed","job.completed"]}'Responses: 201 Endpoint created; `secret` is shown only this once. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
PATCH/v1/webhook_endpoints/{id}
Update a webhook endpoint
Changes the URL and/or the subscribed events. A new URL must be verified again (pending_verification).
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
Responses: 200 The updated endpoint. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
DELETE/v1/webhook_endpoints/{id}
Delete a webhook endpoint
Nothing is delivered to a deleted endpoint.
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
Responses: 204 Deleted. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
POST/v1/webhook_endpoints/{id}/test
Send a test event
Queues a signed webhook.test event to the endpoint (delivered even before verification). Use it to check your signature code.
| Parameter | In | Description |
|---|---|---|
idrequired | path | Object id (`lkp_…`, `job_…` or `we_…`). |
Responses: 202 Test event queued. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
Service catalog
Service catalog (GET /v1/services is authoritative at run time).
Spam reputation (number.spam, alias spam). Whether a phone number appears in spam and nuisance-call
reports: telecom-regulator actions, government nuisance-call complaint data and community spam-report sites, plus
whether the number was recently offered as an unassigned number (a possible spoofed caller ID or fake lead). It is
report-based: no_reports means we hold no reports for the number — it is not a statement that the number is
safe. Countries: US, CA, DE; other numbers → unsupported_country (free). Attributes: risk_level
(high | medium | low | no_reports), risk_score (integer 0–100, higher = more reports), booleans
reason_regulator, reason_government, reason_community, reason_unassigned, hint voip_range (VoIP carrier
range; adds no points), top_category (most frequent report category), first_seen / last_seen (YYYY-MM, when
the number first/last appeared in our data), sources (integer, independent signal classes). Levels: high needs
a regulator action or at least two independent signal classes. Billing: every risk_level including
no_reports is a conclusive answer and is billed; unknown and unsupported_country are free. No report texts
and no names are ever returned.
Live network status (number.hlr, alias hlr) — coming soon. Live home-network query: status
(reachable | unreachable | invalid | unknown), ported, roaming (yes/no only, no location), network,
mcc_mnc, country. Not listed by GET /v1/services and refused with 403 service_disabled until it is switched on.
GET/v1/services
List checks and prices
Without a key: the public catalog. With a key: every check the key's account may use, at the account's prices. Lists active phone and e-mail checks; switched-off checks (e.g. number.hlr, coming soon) are not listed.
curl https://api.mobilevalidate.com/v1/services \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"Responses: 200 Service catalog with prices by mode. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
Keys
Instant personal test keys for developers (no account needed).
POST/v1/test-keys
Get a personal test key
Issues a personal test key (mv_test_…) for a work e-mail address, protected by a Cloudflare Turnstile token from the form at https://mobilevalidate.com/get-test-key. The key works in test mode with any number (never billed, never reaches a data source), including bulk jobs and test-mode webhooks. It is shown once and never returned again. Each address can receive at most 3 test keys in 30 days; after that the answer is 409 test_key_exists. At most 3 requests per network per day, whatever their result (IPv6 networks count per /64). The request also asks for live access, which we review by hand. No authentication.
curl https://api.mobilevalidate.com/v1/test-keys \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym" \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","name":"Ada","company":"Example Ltd","use_case":"Screen sign-up phone numbers","turnstile_token":"0.x…"}'Responses: 201 The key (shown only once). · 409 No more test keys can be issued for this e-mail address right now (at most 3 in 30 days). Keys already issued are never shown again. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request.
System
Service health.
GET/v1/health
Check that the API is up
No authentication. 200 when the API can reach its database, 503 otherwise.
curl https://api.mobilevalidate.com/v1/health \
-H "Authorization: Bearer mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym"Responses: 200 Healthy. · 503 The API cannot reach its database; retry after Retry-After.
Webhook events
lookup.completed— A pending lookup finishedjob.completed— A bulk job finishedjob.failed— A bulk job failed (subscribable; delivery rolling out)job.progress— Progress of a running job (opt-in; delivery rolling out)balance.low— The balance fell below the low-balance threshold (delivery rolling out)limits.cap_reached— A daily identifiers cap or spend cap was reached (delivery rolling out)webhook.verification— Ownership challenge for a new or changed endpointwebhook.test— Test event from POST /v1/webhook_endpoints/{id}/test
Signatures, retries and verification: webhooks guide.

