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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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, the maximum possible cost (max_cost) and its breakdown per check and unit price. Checks in parts too small for the bulk price (WhatsApp: fewer than 132 numbers from one country in the job) are priced at the real-time price and listed with reason: small_batch. Bulk-only checks bill each country of the job at least minimum_checks × the bulk price when it returns an answer; countries with fewer numbers are listed with reason: country_minimum and their minimum is included in 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","+447700900001"],"checks":["whatsapp"]}'Responses: 200 The estimate. · default Error. Branch on `error.code`; `suggestion` (optional) says how to fix the request. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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 (bulk prices; real-time prices for parts too small for the bulk price, see POST /v1/jobs/estimate); 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":["registered@test.mobilevalidate.com"],"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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. The public sandbox key is limited per client IP address instead: it answers sandbox: true, rate_limit with per: "ip", requests_per_minute and requests_per_day (no requests_per_second/burst), jobs.max_numbers 10 and no daily_numbers.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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 looks unassigned — recently offered as an unassigned number, or in a range the national
numbering plan has not assigned (a possible spoofed caller ID or fake lead) — and whether it is a premium-rate
number. 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: all, except sanctioned countries (see below). Attributes: risk_level
(high | medium | low | no_reports), risk_score (integer 0–100, higher = more reports or risk signals), booleans
reason_regulator, reason_government, reason_community, reason_unassigned, hint voip_range (VoIP carrier
range or VoIP number type; adds no points), top_category (most frequent report category; telemarketing = in a
range designated for telemarketing calls), first_seen / last_seen (YYYY-MM, when the number first/last appeared
in our data), sources (integer, independent signal classes), premium_rate (premium-rate or international
shared-cost number — a toll-fraud risk for OTP/verification traffic; adds 20 points but is not a signal class),
hint personal_number (personal/call-forwarding or pager number type; adds no points). Attributes may be added
over time; ignore unknown keys and enum values. 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). Live home-network query: status
(reachable | unreachable | invalid | unknown), ported, roaming (yes/no only, no location), network,
mcc_mnc, country. reachable, unreachable and invalid are conclusive and billed; unknown is free.
Number portability (number.mnp, alias mnp). Whether a mobile number was ported to another network:
porting (ported | not_ported | unknown), mcc_mnc and country of the current network. ported and
not_ported are billed; unknown (including invalid numbers) is free.
Sanctioned countries. Numbers from Cuba, Iran, North Korea, Syria, Russia, Belarus, Venezuela and sanctioned regions are never checked:
every check answers unsupported_country and is free.
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 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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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":"dev@example.com","name":"Ada","company":"Example Ltd","country":"GB","accept_terms":true,"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. A known path called with the wrong method answers `404 not_found` with an `Allow` header listing the methods it accepts.
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.

