{
  "info": {
    "name": "MobileValidate API",
    "_postman_id": "5f0c6d3e-6d1b-4c1e-9a53-6d6f62696c76",
    "description": "MobileValidate API v1.0.0 — know before you send.\n\nPre-filled with the **public sandbox key**: it answers only the documented magic test values (numbers +447700900001–006, e-mails like registered@test.mobilevalidate.com), is never billed and needs no signup.\nMagic values: https://mobilevalidate.com/docs/test-values · Your own test key: https://mobilevalidate.com/get-test-key\nReplace the `apiKey` variable with your own key for anything else. Docs: https://mobilevalidate.com/docs",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://api.mobilevalidate.com",
      "type": "string"
    },
    {
      "key": "apiKey",
      "value": "mv_test_publicSandboxn9ZgneuhR1B9CRfKG3fulym",
      "type": "string"
    },
    {
      "key": "jobId",
      "value": "job_replace_me",
      "type": "string"
    },
    {
      "key": "lookupId",
      "value": "lkp_replace_me",
      "type": "string"
    },
    {
      "key": "webhookEndpointId",
      "value": "we_replace_me",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Lookup",
      "item": [
        {
          "name": "Check up to 100 numbers and e-mail addresses",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Any unique string; retries with the same key are never double-charged."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/lookup",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "lookup"
              ]
            },
            "description": "Check up to 100 numbers and e-mail addresses\n\nRuns 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.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"numbers\": [\n    \"+447700900001\"\n  ],\n  \"checks\": [\n    \"whatsapp\",\n    \"carrier\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Saves the new id for the follow-up requests in this collection.",
                  "if (pm.response.json && pm.response.json().id) pm.collectionVariables.set(\"lookupId\", pm.response.json().id);"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a lookup",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/lookups/:id?wait=0",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "lookups",
                ":id"
              ],
              "query": [
                {
                  "key": "wait",
                  "value": "0",
                  "description": "Seconds (0–30) to wait for pending checks before answering.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{lookupId}}"
                }
              ]
            },
            "description": "Get a lookup\n\nReturns 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)."
          }
        }
      ]
    },
    {
      "name": "Jobs",
      "item": [
        {
          "name": "Estimate a bulk job for free",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Any unique string; retries with the same key are never double-charged."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/jobs/estimate",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "jobs",
                "estimate"
              ]
            },
            "description": "Estimate a bulk job for free\n\nValidates 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.\n\nWith the public sandbox key a job holds at most 10 magic values.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"numbers\": [\n    \"+447700900001\",\n    \"+447700900002\",\n    \"12\"\n  ],\n  \"checks\": [\n    \"whatsapp\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Create a bulk job",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Any unique string; retries with the same key are never double-charged."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/jobs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "jobs"
              ]
            },
            "description": "Create a bulk job\n\nChecks 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.\n\nWith the public sandbox key a job holds at most 10 magic values.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"numbers\": [\n    \"+447700900001\",\n    \"+447700900002\"\n  ],\n  \"emails\": [\n    \"registered@test.mobilevalidate.com\"\n  ],\n  \"checks\": [\n    \"whatsapp\",\n    \"email\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Saves the new id for the follow-up requests in this collection.",
                  "if (pm.response.json && pm.response.json().id) pm.collectionVariables.set(\"jobId\", pm.response.json().id);"
                ]
              }
            }
          ]
        },
        {
          "name": "Get a job",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/jobs/:id?wait=0",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "jobs",
                ":id"
              ],
              "query": [
                {
                  "key": "wait",
                  "value": "0",
                  "description": "Seconds (0–30) to wait for pending checks before answering.",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{jobId}}"
                }
              ]
            },
            "description": "Get a job\n\nStatus, 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.\n\nWith the public sandbox key a job holds at most 10 magic values."
          }
        },
        {
          "name": "Cancel or purge job",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/jobs/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "jobs",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{jobId}}"
                }
              ]
            },
            "description": "Cancel a running job or delete a finished job's results\n\nRunning 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).\n\nWith the public sandbox key a job holds at most 10 magic values."
          }
        },
        {
          "name": "List a job's results",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/jobs/:id/results?registered=true&status=completed&service=&limit=100&after=",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "jobs",
                ":id",
                "results"
              ],
              "query": [
                {
                  "key": "registered",
                  "value": "true",
                  "description": "Only rows whose answer for `service` is true / false / null.",
                  "disabled": true
                },
                {
                  "key": "status",
                  "value": "completed",
                  "description": "Only rows whose `service` check has this status.",
                  "disabled": true
                },
                {
                  "key": "service",
                  "value": "",
                  "description": "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.",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "100",
                  "description": "Rows (numbers and e-mails) per page. A row's checks are never split across pages.",
                  "disabled": true
                },
                {
                  "key": "after",
                  "value": "",
                  "description": "Cursor from the previous page (`next_cursor`).",
                  "disabled": true
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{jobId}}"
                }
              ]
            },
            "description": "List a job's results\n\nOne 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`.\n\nWith the public sandbox key a job holds at most 10 magic values."
          }
        },
        {
          "name": "Download a job's results as CSV or NDJSON",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/jobs/:id/download?format=csv",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "jobs",
                ":id",
                "download"
              ],
              "query": [
                {
                  "key": "format",
                  "value": "csv",
                  "description": "File format."
                }
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{jobId}}"
                }
              ]
            },
            "description": "Download a job's results as CSV or NDJSON\n\nStreams 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.\n\nWith the public sandbox key a job holds at most 10 magic values."
          }
        }
      ]
    },
    {
      "name": "Account",
      "item": [
        {
          "name": "Get the account balance",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/account",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "account"
              ]
            },
            "description": "Get the account balance\n\nBalance, reserved amount and today's usage (UTC) of the key's account. Needs `account:read`."
          }
        },
        {
          "name": "Get limits and remaining allowances",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/limits",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "limits"
              ]
            },
            "description": "Get limits and remaining allowances\n\nRequest rate, request sizes, the daily identifiers cap and the key's daily spend cap. Daily counters reset at 00:00 UTC."
          }
        },
        {
          "name": "Get usage by day or by check",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/usage?from=2026-09-01&to=2026-09-30&group_by=day",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "usage"
              ],
              "query": [
                {
                  "key": "from",
                  "value": "2026-09-01",
                  "description": "First day (UTC)."
                },
                {
                  "key": "to",
                  "value": "2026-09-30",
                  "description": "Last day (UTC), inclusive."
                },
                {
                  "key": "group_by",
                  "value": "day",
                  "description": "One row per day or per check.",
                  "disabled": true
                }
              ]
            },
            "description": "Get usage by day or by check\n\nChecks, 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."
          }
        }
      ]
    },
    {
      "name": "Webhooks",
      "item": [
        {
          "name": "List webhook endpoints",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/webhook_endpoints",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints"
              ]
            },
            "description": "List webhook endpoints\n\nEvery 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`.\n\nThe public sandbox key cannot use webhook endpoints; use your own test key (https://mobilevalidate.com/get-test-key)."
          }
        },
        {
          "name": "Create a webhook endpoint",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Any unique string; retries with the same key are never double-charged."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/webhook_endpoints",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints"
              ]
            },
            "description": "Create a webhook endpoint\n\nRegisters 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.\n\nThe public sandbox key cannot use webhook endpoints; use your own test key (https://mobilevalidate.com/get-test-key).",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"url\": \"https://example.com/hooks/mobilevalidate\",\n  \"events\": [\n    \"lookup.completed\",\n    \"job.completed\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// Saves the new id for the follow-up requests in this collection.",
                  "if (pm.response.json && pm.response.json().id) pm.collectionVariables.set(\"webhookEndpointId\", pm.response.json().id);"
                ]
              }
            }
          ]
        },
        {
          "name": "Update a webhook endpoint",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/webhook_endpoints/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{webhookEndpointId}}"
                }
              ]
            },
            "description": "Update a webhook endpoint\n\nChanges the URL and/or the subscribed events. A new URL must be verified again (`pending_verification`).\n\nThe public sandbox key cannot use webhook endpoints; use your own test key (https://mobilevalidate.com/get-test-key).",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"events\": [\n    \"job.completed\"\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        },
        {
          "name": "Delete a webhook endpoint",
          "request": {
            "method": "DELETE",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/webhook_endpoints/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{webhookEndpointId}}"
                }
              ]
            },
            "description": "Delete a webhook endpoint\n\nNothing is delivered to a deleted endpoint.\n\nThe public sandbox key cannot use webhook endpoints; use your own test key (https://mobilevalidate.com/get-test-key)."
          }
        },
        {
          "name": "Send a test event",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Any unique string; retries with the same key are never double-charged."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/webhook_endpoints/:id/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "webhook_endpoints",
                ":id",
                "test"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "{{webhookEndpointId}}"
                }
              ]
            },
            "description": "Send a test event\n\nQueues a signed `webhook.test` event to the endpoint (delivered even before verification). Use it to check your signature code.\n\nThe public sandbox key cannot use webhook endpoints; use your own test key (https://mobilevalidate.com/get-test-key)."
          }
        }
      ]
    },
    {
      "name": "Catalog",
      "item": [
        {
          "name": "List checks and prices",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/services",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "services"
              ]
            },
            "description": "List checks and prices\n\nWithout 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."
          }
        }
      ]
    },
    {
      "name": "Keys",
      "item": [
        {
          "name": "Get a personal test key",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Any unique string; retries with the same key are never double-charged."
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/test-keys",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "test-keys"
              ]
            },
            "description": "Get a personal test key\n\nIssues 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.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"email\": \"\",\n  \"turnstile_token\": \"\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          }
        }
      ]
    },
    {
      "name": "System",
      "item": [
        {
          "name": "Check that the API is up",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/health",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "health"
              ]
            },
            "description": "Check that the API is up\n\nNo authentication. 200 when the API can reach its database, 503 otherwise."
          }
        }
      ]
    }
  ]
}
