Temp Number API - Phone Number, SMS & OTP
A clean, production-ready REST API to provision virtual phone numbers, receive SMS in real time, and automate OTP verification - built for verification flows, automated onboarding, and any product that needs an inbound SMS or phone number API at scale.
https://api.temp-number.com/v1
Introduction
The Temp Number API is organised around predictable resources, uses standard HTTP verbs, and returns JSON for every response. A single bearer token authorises read and write access to your account only - there is no cross-account access.
Acceptable Use
The API is built for developers: verification and OTP flows, automated onboarding, QA and system testing, and any product that needs inbound SMS or phone numbers at scale.
- Use it for legitimate verification, development and testing only.
- No scams, spam, fraud, or deception. Numbers used for scams or other unusual, abusive activity get the account banned immediately and without notice, associated numbers cancelled, and no refund is due.
- Not for regulated or identity-bound accounts. Our shared, temporary numbers do not support SMS verification for banking, payment, cryptocurrency, government, or other services that verify your legal identity (KYC/AML) — use your own personal mobile number for those.
Authentication
Every request must carry a personal access token in the standard Authorization header:
Authorization: Bearer YOUR_API_TOKEN
- Generate your token from your dashboard under API Access. It is shown in full exactly once at creation - store it safely.
- Tokens are scoped with the
api:accessability and must be sent over HTTPS. Requests without a valid bearer token are rejected with401. - Use a dedicated token per integration so you can revoke one without breaking the others.
Base URL & Versioning
All endpoints live under the permanent /v1 prefix:
https://api.temp-number.com/v1
Additive changes (new fields, new endpoints, new optional parameters) ship without a version bump. Any breaking change ships under a new prefix (/v2) - your integration is never silently moved.
Requests & Responses
- All requests and responses are
application/json. SendAccept: application/jsonto opt into structured error bodies. - Successful responses follow
{ "success": true, "data": …, "meta": {…} }. - Errors follow
{ "success": false, "message": "…" }with the matching HTTP status. - Times are ISO 8601 in UTC. Money values are in USD with two decimals - and are always the user-facing price you pay.
Rate Limits
The API runs under a per-token limit of 60 requests per minute. High-cost endpoints (buy, renew, cancel) have an additional per-action limit on top. Every response carries:
X-RateLimit-Limit- your ceiling for the current window.X-RateLimit-Remaining- calls left in the window.Retry-After- seconds to wait when the response is429.
429. Retry-After is the floor, not the ceiling.Idempotency
State-changing endpoints (POST /numbers/buy, /renew, /cancel) accept an Idempotency-Key header. Send a unique UUID per logical request; retries with the same key are safely de-duplicated within a 24-hour window - even if your network drops mid-request, retrying never charges you twice.
Errors
Errors use standard HTTP status codes with a JSON body:
{
"success": false,
"message": "Insufficient funds to complete this purchase."
}
AI Agents & LLMs
Building with an AI coding assistant (Claude, ChatGPT, Cursor, Copilot)? Hand it the context below and it can integrate this API correctly in one shot - auth, idempotency, rate-limit handling and all.
Ready-to-paste prompt
You are integrating the Temp Number REST API. Read the full, machine-readable reference before writing any code:
- API reference (llms.txt): https://temp-number.com/llms.txt
- OpenAPI spec: https://api.temp-number.com/api.json
- Base URL: https://api.temp-number.com/v1
Rules: authenticate every request with `Authorization: Bearer <YOUR_API_TOKEN>` (created in the dashboard → API Access); send and accept JSON over HTTPS; add a unique `Idempotency-Key` (UUID) header on every POST; on HTTP 429, back off using the `Retry-After` header. All prices are final USD.
Task: <describe what you want to build - e.g. "buy a US number, poll for the OTP, then cancel it">.
https://temp-number.com/llms.txt for an always-current, machine-readable summary of every endpoint, or the OpenAPI spec for a typed contract. Both update automatically with the API.Connect your AI tool
Alongside the REST API we run a Model Context Protocol (MCP) server. Point an AI client at it and it can check your balance, look up pricing and live stock, buy a number and read its SMS — as native tools, with no HTTP code on your side.
/v1 key will not authenticate here, and an MCP key will not work on /v1. Create one under MCP Server in your dashboard, and tick Allow purchases only if you want the agent to be able to spend your balance.
Endpoint
https://mcp.temp-number.com/mcp
Transport is streamable HTTP and authentication is a bearer token. Set your key once as the environment variable TEMPNUMBER_MCP_KEY and the snippets below will pick it up — nothing here ever needs your key pasted into a file or a link.
Claude — claude.ai, Desktop and mobile
Added as a custom connector, authenticating with a request header.
- In Claude, go to Customize › Connectors and choose Add custom connector. On Team and Enterprise plans an owner does this from Organization settings › Connectors.
- Paste the MCP endpoint above as the server URL.
- Set Authentication to None — this server uses a key, not OAuth.
- Open Request headers, pick
authorization, and enter the value asBearerthen a space then your key. Claude sends the value verbatim and adds no scheme of its own, so the wordBearermust be there. - Save, then enable the connector from the + menu in a chat.
Claude Code
One command, then restart the session.
export TEMPNUMBER_MCP_KEY=your-mcp-key
claude mcp add --transport http temp-number \
https://mcp.temp-number.com/mcp \
--header "Authorization: Bearer $TEMPNUMBER_MCP_KEY"
Put the export line in your shell profile so the key stays out of your command history.
ChatGPT on the web
Not available yet.
The ChatGPT desktop app does accept bearer tokens through the Codex config file — see the tab.
Codex CLI & ChatGPT Desktop
Both read the same file: ~/.codex/config.toml
[mcp_servers.temp-number]
url = "https://mcp.temp-number.com/mcp"
bearer_token_env_var = "TEMPNUMBER_MCP_KEY"
The key is read from the environment at run time, so the config file itself stays safe to commit or share.
Cursor
.cursor/mcp.json (or ~/.cursor/mcp.json)
{
"mcpServers": {
"temp-number": {
"url": "https://mcp.temp-number.com/mcp",
"headers": {
"Authorization": "Bearer ${env:TEMPNUMBER_MCP_KEY}"
}
}
}
}
VS Code (Copilot)
.vscode/mcp.json — note the key is servers, not mcpServers.
{
"servers": {
"temp-number": {
"type": "http",
"url": "https://mcp.temp-number.com/mcp",
"headers": {
"Authorization": "Bearer ${input:tempnumber-mcp-key}"
}
}
},
"inputs": [
{
"type": "promptString",
"id": "tempnumber-mcp-key",
"description": "Temp Number MCP key",
"password": true
}
]
}
The one-click link reads the key from TEMPNUMBER_MCP_KEY in your environment. The block above prompts for it instead and stores it in VS Code’s secret storage — use whichever you prefer.
Account
Read your wallet balance and settlement currency.
Get account balance
Returns the authenticated account's available wallet balance and currency. Use it before a purchase to confirm sufficient funds.
Example request
curl --request GET "https://api.temp-number.com/v1/account" \
--header "Accept: application/json" \
--header "Authorization: Bearer $YOUR_API_TOKEN"
Example response
{
"success": true,
"balance": 124.50,
"currency": "USD"
}
Discovery & Pricing
Browse live markets, the exact price you pay per duration, and real-time stock.
List pricing for all countries
The complete live pricing catalog, grouped by country. The `price` field is the final user-facing rate in USD - exactly what your wallet is debited. Upstream provider cost is never exposed.
Example request
curl --request GET "https://api.temp-number.com/v1/pricing" \
--header "Accept: application/json" \
--header "Authorization: Bearer $YOUR_API_TOKEN"
Example response
{
"success": true,
"data": [
{
"country_code": "US",
"country_name": "United States",
"packages": [
{
"number_type": "voip",
"duration": "oneMonth",
"duration_label": "1 Month",
"price": 4.99,
"original_price": 5.99,
"updated_at": null
},
{
"number_type": "voip",
"duration": "threeMonths",
"duration_label": "3 Months",
"price": 12.99,
"original_price": null,
"updated_at": null
},
{
"number_type": "voip",
"duration": "sixMonths",
"duration_label": "6 Months",
"price": 22.99,
"original_price": null,
"updated_at": null
}
]
}
],
"meta": { "count": 1 }
}
Get pricing for one country
Live pricing for a single country. Returns `404` when the country code is valid but has no active route right now - treat it as a transient "out of stock" signal.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
countryCode |
path | Required | ISO 3166-1 alpha-2 country code, e.g. US, GB, CA. |
Example request
curl --request GET "https://api.temp-number.com/v1/pricing/GB" \
--header "Accept: application/json" \
--header "Authorization: Bearer $YOUR_API_TOKEN"
Example response
{
"success": true,
"data": {
"country_code": "GB",
"country_name": "United Kingdom",
"packages": [
{
"number_type": "voip",
"duration": "oneMonth",
"duration_label": "1 Month",
"price": 5.49,
"original_price": null,
"updated_at": null
}
]
}
}
Check inventory availability
Real-time stock for a country + duration so you can preflight a purchase. A green check is a strong signal but the purchase itself is the authoritative check.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
country_code |
query | Required | ISO 3166-1 alpha-2 country code for the market. |
duration |
query | Optional | Package duration key (see /pricing/{country}). Omit for the route default. |
number_type |
query | Optional | Inventory type: voip or non_voip. |
Example request
curl --request GET "https://api.temp-number.com/v1/inventory?country_code=US&duration=oneMonth" \
--header "Accept: application/json" \
--header "Authorization: Bearer $YOUR_API_TOKEN"
Example response
{
"success": true,
"data": {
"country_code": "US",
"duration": "oneMonth",
"number_type": "voip",
"stock": 47,
"available": true,
"status": "In Stock"
}
}
Number Lifecycle
Buy a private number, extend it, or release it back. Money-moving calls are idempotent and replay-safe.
Purchase a private number
Allocates a new private number and settles the order against your wallet atomically. Send an Idempotency-Key so a dropped retry never charges twice. The response shows the exact amount debited and your balance after.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
country_code |
body | Required | A country returned by GET /pricing. |
duration |
body | Required | A duration key from that country's packages[] (e.g. oneMonth). |
number_type |
body | Optional | voip or non_voip. Omit to use the route default. |
Example request
curl --request POST "https://api.temp-number.com/v1/numbers/buy" \
--header "Authorization: Bearer $YOUR_API_TOKEN" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: 5f9b1b3a-c4e9-4f7c-a3b3-1c8b3e8f8f8f" \
--data '{"country_code":"US","duration":"oneMonth","number_type":"voip"}'
Example response
{
"success": true,
"data": {
"id": 1482,
"phone_number": "+14035551234",
"country_code": "US",
"country_name": "United States",
"number_type": "voip",
"status": "active",
"purchase_date": "2026-05-13T17:42:09Z",
"expire_date": "2026-06-13T17:42:09Z"
},
"meta": {
"charged": 4.99,
"currency": "USD",
"wallet_balance_after": 119.51
}
}
Renew a number
Extends a number by the requested package. The new expiry is added to the current expiry, so you can renew early. The renewal is priced at the current site rate for that duration (computed server-side - no client-set amount).
Parameters
| Name | In | Required | Description |
|---|---|---|---|
id |
path | Required | Number id from GET /numbers. |
package |
body | Optional | oneMonth (default), threeMonths, sixMonths, oneYear. |
Example request
curl --request POST "https://api.temp-number.com/v1/numbers/1482/renew" \
--header "Authorization: Bearer $YOUR_API_TOKEN" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: 7f3e8c4a-2d1b-4e8f-91a4-3b9c2d8e1f4a" \
--data '{"package":"threeMonths"}'
Example response
{
"success": true,
"data": {
"id": 1482,
"phone_number": "+14035551234",
"status": "active",
"expire_date": "2026-09-13T17:42:09Z"
},
"meta": {
"charged": 12.99,
"currency": "USD",
"wallet_balance_after": 106.52
}
}
Cancel a number (refund if eligible)
Releases a number and stops further SMS. A full wallet refund is issued when the cancel is requested within 120 minutes of purchase AND the number received no SMS AND it is still active. Outside that window the number is still released, but no refund - check meta.refunded.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
id |
path | Required | Number id from GET /numbers. |
Example request
curl --request POST "https://api.temp-number.com/v1/numbers/1482/cancel" \
--header "Authorization: Bearer $YOUR_API_TOKEN" \
--header "Idempotency-Key: 9a1c7d2e-5f8b-4c3a-9e2d-6b4f1a8c3e7d"
Example response
{
"success": true,
"data": {
"id": 1482,
"phone_number": "+14035551234",
"status": "cancelled"
},
"meta": {
"refunded": 4.99,
"currency": "USD",
"wallet_balance_after": 124.50
}
}
Your Numbers & SMS
List the numbers you own and read the SMS they receive.
List your numbers
Every number on your account, newest first. Filter by lifecycle with ?status= - use expiring_soon (within 10 days of expiry) to drive renewal prompts.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
status |
query | Optional | active, expiring_soon, expired, cancelled, or all (default). |
Example request
curl --request GET "https://api.temp-number.com/v1/numbers?status=expiring_soon" \
--header "Accept: application/json" \
--header "Authorization: Bearer $YOUR_API_TOKEN"
Example response
{
"success": true,
"data": [
{
"id": 1482,
"phone_number": "+14035551234",
"country_code": "US",
"country_name": "United States",
"number_type": "voip",
"status": "active",
"purchase_date": "2026-05-13T17:42:09Z",
"expire_date": "2026-06-13T17:42:09Z"
}
],
"meta": { "count": 1, "status": "expiring_soon" }
}
Get number details + recent SMS
Full details of one number together with the SMS it has received, newest first. You receive the raw message body - OTP parsing is up to you. Returns 404 (not 403) if the id isn't yours.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
id |
path | Required | Number id from GET /numbers. |
Example request
curl --request GET "https://api.temp-number.com/v1/numbers/1482/sms" \
--header "Accept: application/json" \
--header "Authorization: Bearer $YOUR_API_TOKEN"
Example response
{
"success": true,
"data": {
"number": {
"id": 1482,
"phone_number": "+14035551234",
"country_code": "US",
"country_name": "United States",
"number_type": "voip",
"status": "active",
"purchase_date": "2026-05-13T17:42:09Z",
"expire_date": "2026-06-13T17:42:09Z"
},
"messages": [
{
"id": 9912,
"from": "+18005550199",
"body": "Your code is 432901",
"received_at": "2026-05-13T17:43:14Z"
}
]
},
"meta": { "count": 1 }
}
Receive SMS by phone number
Cursor-paginated SMS for a number you own, addressed by its E.164 phone number rather than its id. Best for high-volume polling. Cursors are opaque - pass meta.nextCursor back to page forward.
Parameters
| Name | In | Required | Description |
|---|---|---|---|
phoneNumber |
query | Required | The number in E.164 (or digits), e.g. +14035551234. |
limit |
query | Optional | Page size 1-100 (default 50). |
cursor |
query | Optional | Opaque pagination cursor from a previous response. |
Example request
curl --request GET "https://api.temp-number.com/v1/receive-sms?phoneNumber=%2B14035551234" \
--header "Accept: application/json" \
--header "Authorization: Bearer $YOUR_API_TOKEN"
Example response
{
"success": true,
"data": {
"phoneNumber": "+14035551234",
"purchaseStatus": "active",
"messages": [
{
"id": 1842,
"from": "WhatsApp",
"to": "+14035551234",
"message": "Your verification code is 483920.",
"receivedAt": "2026-05-13T17:43:14Z"
}
]
},
"meta": {
"count": 1,
"pageSize": 50,
"hasMore": false,
"nextCursor": null,
"prevCursor": null,
"requestedAt": "2026-05-13T17:43:20Z"
}
}
Ready to build?
Generate a token and make your first call in under a minute.