Developer Platform

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.

BASE URL 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.

ProtocolHTTPS · JSON
AuthBearer token
Versionv1 (stable)
Endpoints10 live

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.
We monitor for abuse. Full conditions are in our Terms of Service.

Authentication

Every request must carry a personal access token in the standard Authorization header:

http
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:access ability and must be sent over HTTPS. Requests without a valid bearer token are rejected with 401.
  • Use a dedicated token per integration so you can revoke one without breaking the others.
Treat your token like a password. Rotate it immediately if it has ever been logged, committed to source control, or shared.

Base URL & Versioning

All endpoints live under the permanent /v1 prefix:

base url
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. Send Accept: application/json to 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.
Pricing responses never expose upstream provider names or wholesale cost. The only price you ever see is the one charged to your wallet - safe to show directly to your own users.

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 is 429.
Implement exponential backoff with jitter on 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:

response.json
{
  "success": false,
  "message": "Insufficient funds to complete this purchase."
}
401Missing / invalid token
404Resource not on your account
422Validation / funds / stock
429Rate limited - back off

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.

llms.txt OpenAPI spec

Ready-to-paste prompt

prompt.md
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">.
Point your agent at 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.

Account

Read your wallet balance and settlement currency.

GET /account

Get account balance

Returns the authenticated account's available wallet balance and currency. Use it before a purchase to confirm sufficient funds.

Example request

terminal
curl --request GET "https://api.temp-number.com/v1/account" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer $YOUR_API_TOKEN"

Example response

response.json
{
  "success": true,
  "balance": 124.50,
  "currency": "USD"
}

Discovery & Pricing

Browse live markets, the exact price you pay per duration, and real-time stock.

GET /pricing

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

terminal
curl --request GET "https://api.temp-number.com/v1/pricing" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer $YOUR_API_TOKEN"

Example response

response.json
{
  "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/{countryCode}

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

NameInRequiredDescription
countryCode path Required ISO 3166-1 alpha-2 country code, e.g. US, GB, CA.

Example request

terminal
curl --request GET "https://api.temp-number.com/v1/pricing/GB" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer $YOUR_API_TOKEN"

Example response

response.json
{
  "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
      }
    ]
  }
}
GET /inventory

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

NameInRequiredDescription
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

terminal
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

response.json
{
  "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.

POST /numbers/buy

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

NameInRequiredDescription
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

terminal
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

response.json
{
  "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
  }
}
POST /numbers/{id}/renew

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

NameInRequiredDescription
id path Required Number id from GET /numbers.
package body Optional oneMonth (default), threeMonths, sixMonths, oneYear.

Example request

terminal
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

response.json
{
  "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
  }
}
POST /numbers/{id}/cancel

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

NameInRequiredDescription
id path Required Number id from GET /numbers.

Example request

terminal
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

response.json
{
  "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.

GET /numbers

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

NameInRequiredDescription
status query Optional active, expiring_soon, expired, cancelled, or all (default).

Example request

terminal
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

response.json
{
  "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 /numbers/{id}/sms

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

NameInRequiredDescription
id path Required Number id from GET /numbers.

Example request

terminal
curl --request GET "https://api.temp-number.com/v1/numbers/1482/sms" \
  --header "Accept: application/json" \
  --header "Authorization: Bearer $YOUR_API_TOKEN"

Example response

response.json
{
  "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 }
}
GET /receive-sms

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

NameInRequiredDescription
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

terminal
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

response.json
{
  "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.

Sign in to start