Fetch SMSAPI v1

SMS verification API reference

Rent non-VOIP US numbers and fetch SMS verification codes programmatically — authentication, endpoints, webhooks, and the live service catalog.

Introduction

The Fetch SMS API lets you rent real US non-VOIP phone numbers and receive SMS verification codes programmatically. It is a JSON REST API over HTTPS.

Conventions
Base URLstringhttps://api.fetchsms.com/v1
MoneyintegerEvery amount is in integer US cents (7000 = $70.00).
TimestampsstringISO-8601 in UTC, e.g. 2026-06-17T22:14:05Z.
IDsstringResource ids are UUIDs; services also have a short numeric id.

The fastest path: list services, create a verification, then poll it until the code arrives.

# 1. Pick a service id
curl https://api.fetchsms.com/v1/services

# 2. Rent a number for it
curl https://api.fetchsms.com/v1/verifications \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service": 4}'

# 3. Poll until "code" is populated (most codes arrive in seconds)
curl https://api.fetchsms.com/v1/verifications/<id> \
  -H "Authorization: Bearer YOUR_API_KEY"

Authentication

Authenticate programmatic verification and rental requests with an API key in the Authorization header as a bearer token. Create and rotate keys on the API page of your dashboard. Keys are shown only once, so store them securely.

Authorization: Bearer YOUR_API_KEY

Dashboard, account, wallet, support, admin, and API-key management routes require a dashboard session token and reject API keys — the one exception is GET /v1/wallet/balance, which accepts an API key so you can check funds before buying. The public catalog endpoints (GET /v1/services and GET /v1/services/quote) do not require a key.

Errors & rate limits

Errors use standard HTTP status codes and a JSON body with a single field:

{ "detail": "Telegram is out of stock for short-term verifications" }
Status codes
200 / 201successRequest succeeded (201 on resource creation).
400bad requestMalformed input or a business-rule violation.
401unauthorizedMissing, invalid, or revoked credential.
402payment requiredInsufficient wallet balance for the purchase.
403forbiddenCredential is valid but not allowed for the endpoint.
404not foundUnknown service, or a resource you do not own.
409conflictOut of stock, or code already received (cannot cancel).
422unprocessableInvalid duration or parameter value.
429rate limitedToo many requests — slow down and retry.

Rate limit: 100 requests/second per API key. Poll for codes at a sane interval (every 2–5 seconds is plenty).

Services

Fetch SMS has two separate products — short-term and long-term are priced and sold independently:

Products
Short-term verificationper serviceA number for one code, priced per service (WhatsApp, Telegram, …). Each has its own numeric id — see Short-term services.
Long-term rentalsingle productOne flat-priced number that works for any service — the "unlimited-services" product (id 1). There is no per-service long-term option.

List the catalog with GET /v1/services. Anywhere the API takes a service, pass the stable numeric id. Slugs like telegram are also accepted for compatibility.

GET/v1/services

Returns an array of services ordered for display. No authentication required.

Response — each item
idintegerStable numeric public id (1…N) — the recommended reference for every endpoint.
slugstringCompatibility reference, e.g. "telegram".
namestringDisplay name, e.g. "Telegram".
price_centsintegerShort-term verification price (also the long-term base daily rate).
long_pricesobjectLong-term price map {"1":300,…} in cents — empty {} except on the Unlimited service.
short_availableintegerNumbers available right now for verifications.
long_availableintegerPristine numbers available right now for Unlimited rentals.
curl https://api.fetchsms.com/v1/services
[
  {
    "id": 2,
    "slug": "whatsapp",
    "name": "WhatsApp",
    "price_cents": 140,
    "long_prices": {},
    "short_available": 200,
    "long_available": 100
  }
]

Long-term rentals are the single Unlimited product, so only it carries a populated long_prices map — every short-term service returns {}. See the full id ↔ service mapping under Short-term services.

GET/v1/services/area-codes

The US area codes available in the pool right now — the options when renting with a custom area code (+$0.10). No authentication required.

Query
modestring"short" (default) or "long". Long-term lists only pristine, never-used numbers.
serviceinteger or stringOptional service reference — returns the codes available for that specific short-term service.
curl "https://api.fetchsms.com/v1/services/area-codes?mode=short&service=2"
["212", "332", "415", "628", "917"]

Pricing & quotes

Short-term verifications are priced per service — each costs that service's verification price (price_cents).

Long-term rentals are a single flat-priced product: one dedicated number that works for any service, billed per term. The price does not depend on which services you use the number for.

Long-term rental price · one number, any service
1 day$3.00
7 days$6.00
30 days$12.00
90 days$25.00
365 days$90.00

A custom area code adds a flat $0.10 surcharge to either product.

GET/v1/services/quote

Compute the exact price before you buy. No authentication required.

Parameters
serviceinteger or string · requiredStable numeric id recommended; slug accepted for compatibility. Use id 1 for long mode.
modestring · required"short" for a verification, "long" for a rental.
daysintegerTerm length for long mode: 1, 7, 30, 90, or 365.
custom_area_codebooleantrue to include the $0.10 area-code surcharge (default false).
curl "https://api.fetchsms.com/v1/services/quote?service=4&mode=short&custom_area_code=true"
{
  "service": "telegram",
  "mode": "short",
  "days": null,
  "base_daily_cents": 70,
  "discount_pct": 0,
  "per_day_cents": null,
  "surcharge_cents": 10,
  "total_cents": 80
}
curl "https://api.fetchsms.com/v1/services/quote?service=1&mode=long&days=30"
{
  "service": "unlimited-services",
  "mode": "long",
  "days": 30,
  "base_daily_cents": 300,
  "discount_pct": 87,
  "per_day_cents": 40,
  "surcharge_cents": 0,
  "total_cents": 1200
}

Verifications (short-term)

A verification reserves a number to receive your verification code inside a fixed 15-minute window. The wallet is debited up front; if the window closes (or you cancel) before any code arrives, the charge is automatically refunded — you are only charged on receipt.

Verifications are per service: the code is released only when the inbound SMS matches the service you purchased — a code for a different service is not shown and the verification keeps waiting. The response and webhook carry the code only, never the message body.

POST/v1/verifications
Body
serviceinteger or string · requiredStable numeric id from GET /v1/services is recommended; slug accepted for compatibility.
area_codestringOptional 3-digit US area code, e.g. "332" (+$0.10).
curl https://api.fetchsms.com/v1/verifications \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"service": 4, "area_code": "332"}'
{
  "id": "9f3e1c2a-…",
  "ref": "v_8R3p2K",
  "service": "telegram",
  "service_name": "Telegram",
  "number": "(332) 555-0184",
  "code": null,
  "status": "waiting",
  "cost_cents": 70,
  "created_at": "2026-06-17T22:14:05Z",
  "expires_at": "2026-06-17T22:29:05Z"
}

status is one of waiting, received, expired, cancelled. Errors: 402 insufficient balance, 404 unknown service, 409 out of stock.

GET/v1/verifications/{id}

Fetch one verification — poll it until code is non-null and status is received. code is the most recent code received; code_count is how many have arrived in the window so far.

curl https://api.fetchsms.com/v1/verifications/9f3e1c2a-… \
  -H "Authorization: Bearer YOUR_API_KEY"
{ "id": "9f3e1c2a-…", "status": "received", "code": "482910", "code_count": 1, … }
GET/v1/verifications/{id}/messages

Every code this verification has received inside its 15-minute window, newest first. The number stays yours for the whole window, so if more than one code arrives — for example a re-send, or a second login attempt — each is captured here, while code on the verification itself is only the latest. Codes are returned as code + received_at only — the message body is never exposed for short-term verifications.

curl https://api.fetchsms.com/v1/verifications/9f3e1c2a-…/messages \
  -H "Authorization: Bearer YOUR_API_KEY"
[
  {
    "id": "…",
    "code": "552310",
    "received_at": "2026-06-17T22:21:07Z"
  },
  {
    "id": "…",
    "code": "482910",
    "received_at": "2026-06-17T22:18:44Z"
  }
]
GET/v1/verifications?tab=active

List your verifications. tab is active (default) or history.

curl "https://api.fetchsms.com/v1/verifications?tab=active" \
  -H "Authorization: Bearer YOUR_API_KEY"
POST/v1/verifications/{id}/cancel

Cancel a waiting verification and refund the charge. Returns 409 once a code has arrived.

curl -X POST https://api.fetchsms.com/v1/verifications/9f3e1c2a-…/cancel \
  -H "Authorization: Bearer YOUR_API_KEY"

Wallet

Purchases are paid from your prepaid wallet. Check your balance before buying to avoid a 402. Deposits and ledger history are dashboard-only.

GET/v1/wallet/balance

Your spendable balance. Reads a single row, so it costs the same whether you have ten transactions or a hundred thousand — safe to call before every purchase.

Response
balance_centsintegerSpendable balance in cents. 0 if you have never funded the account.
curl https://api.fetchsms.com/v1/wallet/balance \
  -H "Authorization: Bearer YOUR_API_KEY"

{ "balance_cents": 12345 }

Amounts are always integer cents. A purchase that costs more than your balance returns 402 with a detail message, and nothing is charged.

Webhooks

Instead of polling, register an endpoint to receive events the moment they happen. Add and manage endpoints on the API page. Each delivery is a POST with a JSON body.

Events
sms.receivedeventA code/SMS arrived on a verification or rental number.
rental.expiredeventA long-term rental reached the end of its term.

Delivery headers:

Parameters
X-FetchSMS-EventstringThe event type, e.g. "sms.received".
X-FetchSMS-SignaturestringHMAC-SHA256 hex of the raw body, keyed by your endpoint secret.

Example sms.received payload:

{
  "event": "sms.received",
  "data": {
    "verification_id": "9f3e1c2a-…",
    "ref": "v_8R3p2K",
    "number": "(332) 555-0184",
    "sender": "Telegram",
    "code": "482910",
    "detected_service": "Telegram",
    "received_at": "2026-06-17T22:15:30Z"
  },
  "created_at": "2026-06-17T22:15:30Z"
}

Short-term verification events carry the code only — never the message body. A long-term rental event carries rental_id (instead of verification_id) and includes the full body. A rental.expired payload carries rental_id, ref, and number.

Verify the signature before trusting a delivery:

import crypto from 'node:crypto'

function verify(rawBody, signature, endpointSecret) {
  const expected = crypto
    .createHmac('sha256', endpointSecret)
    .update(rawBody)
    .digest('hex')
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}

Short-term services

Every short-term verification service with its stable numeric id, slug, and price — pass the id to POST /v1/verifications. Live per-service stock is returned by GET /v1/services (the short_available field). The long-term unlimited-services rental product is not a short-term service and is excluded here (see Pricing).

IDSlugServiceVerification price
Loading catalog…