Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.0.3
info:
title: Numbers Online Phone Intelligence API
description: "\nPhone number parsing, validation, and inbound caller-intelligence as a supplementary signal.\n\n## Authentication\n\nGet a key via self-service signup:\n\n```\nPOST /api/v1/account/signup {}\n```\n\nThe response returns your key exactly once. Keys look like `nol_…` and are stored\nonly as a hash — we cannot recover a lost key, so save it. Send it on every request\nin one of these headers:\n\n- `Authorization: Bearer nol_YOUR_KEY`\n- `X-API-Key: nol_YOUR_KEY`\n\nKeyless endpoints (everything else requires a key): `POST /api/v1/account/signup`,\n`GET /api/health`, `GET /api/spec`, `GET /api/v1/publickey`,\n`GET /api/v1/receipts/{id}` (the unguessable id is the credential), and the MCP\nserver's public discovery methods (`initialize`, `ping`, `tools/list`).\n\n**Canonical URL form (decision 2026-06-11):** the long `/api/v1/*` paths in this\nspec are canonical. The bare `/v1/*` spelling is a tolerated rewrite alias for\nheader-less PBX URL fields only. HMAC-signed operator\
\ requests MUST use\n`/api/v1/*` — request signing canonicalizes the post-rewrite long path, so a\nsignature computed over the bare form will not verify.\n\nThe interactive \"try it\" widgets on Numbers Online call these endpoints through a\nfirst-party server-side demo proxy, so no real key is ever shipped to the browser.\nThat proxy is an internal convenience for the website only — integrate against the\ndocumented endpoints with your own key.\n\n## Which lookup do I want?\n\nSeven surfaces answer \"who/what is this number\" — they differ in direction, side\neffects, price, and how they fail. Pick by row:\n\n| endpoint | direction | what you get | side effects | price (standard tier) | limit & failure mode | response auth |\n|---|---|---|---|---|---|---|\n| `GET /api/v1/lookup/{e164}` | inbound (or any) | JSON: validity, line type, carrier, CNAM, `risk{}` | none | `$0.004` fresh CNAM dip / `$0.002` without | account-pooled 429 + `Retry-After`; prepaid 402 before any work | unsigned\
\ |\n| `POST /api/v1/lookup/batch` | bulk (≤100) | same per number + summary | none | same, per number | pooled 429; whole-batch 402 precheck | unsigned |\n| `POST /api/v1/inbound/lookup` | inbound, answer-time | identity type, display label, action hint, full-blend `risk{}`, receipt | mints a single-use `receipt_id` (spendable on `/api/v1/report`) | `$0.004` | pooled 429; prepaid 402; fail-open neutral body on internal errors | **Ed25519-signed** + receipt |\n| `POST /api/v1/outbound/lookup` (alias `/api/v1/precall/lookup`) | outbound, pre-dial | DNC scrub (`SUPPRESS`/`NO_MATCH`/`UNKNOWN`) + `dial_risk` + `cost_estimate` (voice & SMS) | hashed provenance edge when `from` is enrolled | free (bundled) | fair-use pool 429 + `Retry-After`; fail-open `UNKNOWN` | unsigned |\n| `GET /api/v1/cid/{number}` | inbound, PBX | plain-text caller name only | none | same as lookup | EVERY failure is the text sentinel `UNAVAILABLE` (status still meaningful) | plain text, unsigned |\n| `POST /api/v1/sbc/redirect`\
\ | inbound, SIP edge | 302 SIP redirect decision + advisory headers | none | `$0.010` | fail-open `allow` on any error (never blocks a call) | unsigned |\n| `POST /api/v1/mcp` | AI agents | lookup/risk/DNC tools over JSON-RPC | per-tool | `$0.015` per tool call | JSON-RPC errors; transport auth uses the flat error shape | unsigned |\n\nEvery risk read on every row is a supplementary, low-confidence signal — never a\nverdict. On live call paths, prefer the fail-open rows (`cid`, `sbc`, outbound).\n\n## Billing\n\n- **Free tier** — no charge; throttled by low per-key rate limits. Good for trying\n the API and low-volume use.\n- **Standard tier** — prepaid credits, billed per dip against your balance:\n number lookup `$0.004` with a fresh wholesale CNAM dip or `$0.002` when served\n without one (cache hit or no CNAM supplier configured), inbound lookup `$0.004`,\n list scrub `$0.001` per number, the bundled\n AI-voice-agent call — MCP `tools/call` and the Vapi/Retell webhooks — `$0.015`,\n\
\ and the SBC/SIP redirect decision `$0.010`. Invalid numbers and all\n parsing/reference endpoints are free on every tier.\n\n### Billing observability headers\n\nBilled responses carry three headers, sourced from the metering write itself:\n`X-Billed-Micros` (what THIS request cost, in microdollars), `X-Balance-Micros`\n(your remaining prepaid balance after it), and `X-Billing-Endpoint` (the billing\nclass — e.g. `lookup` vs `lookup_enriched`, which is how you observe the\nfresh-dip vs cache price split per call; batch responses list both classes and\nsum the debits). The headers are ABSENT when nothing was debited: free/enterprise\ntiers, invalid numbers, idempotent retries, or when metering failed open.\n\nAdd credit with `POST /api/v1/account/topup` (Stripe Checkout, `$5` minimum).\nWhen a standard-tier balance is exhausted, billed endpoints return **402** — top up\nto resume. Check your balance and recent usage any time with `GET /api/v1/account`.\n\nVerifying a number is separate\
\ from this prepaid API credit. **Personal** number\nverification is a one-time `$9` charge. **Business** number verification is a\n`$29/year` auto-renewing subscription (renews automatically each year; cancel\nanytime) — this is what raises an account's pooled rate limits and report quota.\n\n## Rate Limiting\n\nRate limits are **account-pooled and business-scaled** — they are shared across\nall of an account's keys (not per key), and are recomputed from live state. The\nfree / unverified floor is **10 lookups/min, 50/day, and 10 reports/day**. Each\nverified business number on the account adds **+60/min and +2,000/day lookups and\n+100/day reports**, pooled across every key. Personal ($9) verification does not\nraise these limits. When you exceed a limit the API returns **429** with a\n`Retry-After` header (seconds).\n\n## Error codes\n\nJSON error bodies are flat: `{ \"error\": \"<human prose>\", \"code\": \"<machine enum>\" }`,\nplus `retry_after_seconds` on 429s and `balance_micros`/`topup_url`/`topup_min_cents`\n\
on insufficient-balance 402s. Switch on `code`, never on the prose. The codes:\n\n| code | HTTP | meaning |\n|---|---|---|\n| `missing_key` | 401 | No API key in the request |\n| `invalid_key` | 401 | Key unknown (or revoked — indistinguishable by design) |\n| `use_case_forbidden` | 403 | Valid key, not enabled for this endpoint's use case |\n| `rate_limited_key` | 429 | Per-key per-minute window exceeded |\n| `rate_limited_pool` | 429 | Account-pooled budget exhausted (lookups, pre-call, daily reports) |\n| `rate_limited_ip` | 429 | Too many failed auth attempts from your IP |\n| `signature_invalid` | 401 | Operator request signing required, missing, or failed |\n| `insufficient_balance` | 402 | Prepaid balance cannot cover the request — top up |\n| `account_suspended` | 403 | Account suspended by the operator; topping up will not help |\n| `paid_verification_required` | 402 | The remedy is a paid number verification, not a top-up |\n| `receipt_invalid` | 409 | Missing, already-used,\
\ or mismatched `receipt_id` |\n\nChannel-specific surfaces keep their own documented contracts instead of this shape:\n`/api/v1/cid` (plain text), the Retell/Vapi webhooks (always 200), the SBC\nredirect's fail-open `allow` bodies, and MCP JSON-RPC message-level errors (MCP\ntransport-level HTTP auth errors do use this shape).\n\n## Schema versioning\n\nEvery JSON shape this platform owns carries a `schema_version` — a date-stamped\nidentifier **unique to that shape** (a given date never identifies two different\nshapes). The bump rule: **additive changes never bump the version; removing,\nrenaming, or retyping a field bumps it.** Generated clients must treat\n`schema_version` as an open string, never a closed enum.\n\nTwo version classes:\n\n- **Negotiable** — unsigned live responses (lookup, batch, precall, scrub,\n report, account…). The version may advance over time; additive fields appear\n without a bump.\n- **Stamped** — Ed25519-signed artifacts (inbound lookup responses, receipts,\n\
\ evidence bundles). The version is fixed into the signed bytes at signing time\n and is never renegotiated — a verifier re-checks exactly what was signed.\n\nProtocol envelopes are exempt: MCP JSON-RPC frames (the embedded tool result is\nversioned instead) and the Vapi/Retell vendor webhook shapes. `/api/v1/cid` is\nplain text and unversioned by design.\n\n### Version changelog\n\n| schema_version | shape |\n|---|---|\n| `2026-05-31` | Inbound lookup response (stamped) |\n| `2026-06-03` | Lookup response — also receipts (pre-policy collision; both frozen) |\n| `2026-06-06` | SBC advisory — also evidence bundles (pre-policy collision; both frozen) |\n| `2026-06-11` | Pre-call lookup (added `dnc_channel`, per-channel DNC scrub) |\n| `2026-06-12` | Batch lookup envelope (introduced) |\n| `2026-06-13` | Report ok-body (introduced) |\n| `2026-06-14` | Pre-call enroll ok-body (introduced) |\n| `2026-06-15` | Account group envelope (introduced; GET and PATCH share the shape) |\n| `2026-06-16`\
\ | Key-lifecycle ok-bodies (introduced; list/mint/update/rotate share the shape) |\n| `2026-06-17` | Signup ok-body (introduced; adds the structured key descriptor) |\n| `2026-06-18` | Parse response (introduced; v1 promotion of `/api/parse` minus the `{success:}` envelope) |\n| `2026-06-19` | Parse batch response (introduced; v1 promotion of `/api/parse/bulk`) |\n| `2026-06-20` | Scrub response (introduced; v1 promotion of `/api/scrub`) |\n| `2026-06-21` | Countries response (introduced; v1 promotion of `/api/countries`) |\n| `2026-06-22` | Account phones resource (introduced; the list and the PATCH share the shape) |\n| `2026-06-23` | Pre-call lookup (cost_estimate restructured: per-channel voice + SMS rates with per-provider breakdown; supersedes the flat per-minute `2026-06-11` shape) |\n\nAdditive change 2026-06-11 (no version bumps, per the bump rule): the\n`risk: { score, level, model }` object was added to the lookup family, the\ninbound lookup (inside the signed body), the\
\ SBC advisory, and — as a `model`\nfield — pre-call's `dial_risk`. See **Risk models** below.\n\n## Risk models\n\nThe platform runs more than one risk model, and historically each surface used\nits own field name without saying which model fed it. Every JSON scoring surface\nnow also carries `risk: { score, level, model }` (additive; the legacy fields\nare frozen forever — copy-paste-distributed parsers hard-match `spam_score`,\nand inbound's `risk_score` is a *different model* under a similar name):\n\n| model | scale | where | sources |\n|---|---|---|---|\n| `first_party_plus_restricted_sources` | 1–99 | `/api/v1/lookup` (+batch), `/api/v1/cid`, SBC advisory, Retell/Vapi variables | First-party reports/reviews/verification + external evidence restricted to open-dataset / regulator-list sources (FTC DNC, FCC complaints, BNetzA enforcement) |\n| `first_party_plus_external` | 0–100 | `/api/v1/inbound/lookup` (signed body) | The full blend, including crowd directories — broader coverage,\
\ mixed provenance |\n| `dial_structural` | 0–100 | `/api/v1/outbound/lookup` `dial_risk` | Outbound structural prior (premium/satellite/IRSF cover) + dynamic fraud observations — the risk of DIALING, not of the caller |\n\nBanding is shared (`<40` low, `<70` medium, `≥70` high; null → `unknown`).\nThe SBC `flag` decision threshold is a separate, operator-overridable policy\nknob (default 80) — `level: \"high\"` does not automatically flag. The numeric\nscales are deliberately not unified; `model` is what tells them apart. Every\nscore remains a labeled, low-confidence supplementary signal — never a verdict.\n\n## Community reporting\n\n`POST /api/v1/report` is the give-to-get half of the community sensor: a key-gated\nendpoint for reporting a number with one or more tags (tags only — no free-text\nbody). Each report spends a single-use `receipt_id` from a prior\n`POST /api/v1/inbound/lookup` on the same number — the receipt is an anti-replay\nnonce and rate control, **not** proof a\
\ call occurred. Accounts with a verified\nbusiness number report in the **accountable** lane (reporter-weighted, earns\ncredibility); free / personal accounts report in the **crowd** lane (a bounded,\ndeferring, credibility-firewalled supplementary signal that cannot sink a verified\nnumber on its own). The daily report quota is pooled per account: 10/day on the\nfree floor, +100/day per verified business number.\n "
version: 1.0.0
contact:
name: Phone Numbers Online
url: https://numbers.online
x-apievangelist-provenance:
harvested: '2026-09-19'
method: searched
source: https://numbers.online/api/spec
http_status: 200
content_type: application/json
note: 'Verbatim harvest of the provider-published OpenAPI 3.0.3 (56 operations, 24 schemas). The JSON original is archived at openapi/_original/numbers-online-openapi.json; this file is the same document serialized as YAML. Ownership: servers[0] is https://numbers.online, info.contact.url is https://numbers.online, and the provider llms.txt/robots.txt/docs all name /api/spec as the source of truth.'
servers:
- url: https://numbers.online
description: Production server
- url: http://localhost:3000
description: Development server
tags:
- name: Account
description: 'Self-service API account: signup, balance, usage, credit top-ups, and the key lifecycle. Account-management endpoints require an account-level key with the ''manage'' use case (every self-service key holds it unless deliberately narrowed; the per-key signing config is exempt).'
- name: Parsing
description: Phone number parsing and validation endpoints
- name: Lookup
description: 'Number lookup: line type, range carrier, CNAM, verstat, and a supplementary spam signal'
- name: PBX
description: Plain-text caller-id lookup for header-less PBX integrations (FreeSWITCH mod_cidlookup and similar)
- name: Inbound
description: Inbound caller-intelligence lookup for operators, PBX, and softphones
- name: Outbound
description: Outbound pre-call checks (scrub + call-provenance) and number enrollment for spoofing-defense
- name: Community reporting
description: Key-gated spam/scam reporting — the give-to-get half of the community sensor (receipt-gated, tags-only, lane-scoped supplementary signals)
- name: MCP
description: 'Model Context Protocol server for AI voice agents (Vapi, Retell, Pipecat, LiveKit): read-only phone-intelligence tools over Streamable HTTP'
- name: Webhooks
description: AI-voice-agent webhook adapters (Retell inbound, Vapi custom tool) over the same lookup backend
- name: SBC / SIP
description: SIP redirect-server decisions for session border controllers (Kamailio, OpenSIPS, dSIPRouter, Sansay, Oracle/Acme Packet, ProSBC) via the operator-run shim recipe, plus an FCC robocall-mitigation evidence bundle — a supplementary call-setup signal, fail-open
- name: Trust
description: Contact-suppression preference lookups
- name: MSP
description: 'Multi-tenant control plane: per-tenant sub-keys, usage rollups, and suppression lists for MSPs and PBX resellers'
- name: Receipts
description: Signed, privacy-safe lookup receipts (Ed25519) — verifiable "checked as of T" evidence
- name: Reference
description: Reference data and examples
# --- truncated at 32 KB (191 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/numbers-online/refs/heads/main/openapi/numbers-online-openapi.yml