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.
| Base URL | string | https://api.fetchsms.com/v1 |
| Money | integer | Every amount is in integer US cents (7000 = $70.00). |
| Timestamps | string | ISO-8601 in UTC, e.g. 2026-06-17T22:14:05Z. |
| IDs | string | Resource 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_KEYDashboard, account, wallet, support, admin, and API-key management routes require a dashboard session token and reject API keys. 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" }| 200 / 201 | success | Request succeeded (201 on resource creation). |
| 400 | bad request | Malformed input or a business-rule violation. |
| 401 | unauthorized | Missing, invalid, or revoked credential. |
| 402 | payment required | Insufficient wallet balance for the purchase. |
| 403 | forbidden | Credential is valid but not allowed for the endpoint. |
| 404 | not found | Unknown service, or a resource you do not own. |
| 409 | conflict | Out of stock, or code already received (cannot cancel). |
| 422 | unprocessable | Invalid duration or parameter value. |
| 429 | rate limited | Too 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:
| Short-term verification | per service | A number for one code, priced per service (WhatsApp, Telegram, …). Each has its own numeric id — see Short-term services. |
| Long-term rental | single product | One 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.
/v1/servicesReturns an array of services ordered for display. No authentication required.
| id | integer | Stable numeric public id (1…N) — the recommended reference for every endpoint. |
| slug | string | Compatibility reference, e.g. "telegram". |
| name | string | Display name, e.g. "Telegram". |
| price_cents | integer | Short-term verification price (also the long-term base daily rate). |
| long_prices | object | Long-term price map {"1":300,…} in cents — empty {} except on the Unlimited service. |
| short_available | integer | Numbers available right now for verifications. |
| long_available | integer | Pristine 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.
/v1/services/area-codesThe US area codes available in the pool right now — the options when renting with a custom area code (+$0.10). No authentication required.
| mode | string | "short" (default) or "long". Long-term lists only pristine, never-used numbers. |
| service | integer or string | Optional 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.
| 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.
/v1/services/quoteCompute the exact price before you buy. No authentication required.
| service | integer or string · required | Stable numeric id recommended; slug accepted for compatibility. Use id 1 for long mode. |
| mode | string · required | "short" for a verification, "long" for a rental. |
| days | integer | Term length for long mode: 1, 7, 30, 90, or 365. |
| custom_area_code | boolean | true 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 for a single 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.
/v1/verifications| service | integer or string · required | Stable numeric id from GET /v1/services is recommended; slug accepted for compatibility. |
| area_code | string | Optional 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.
/v1/verifications/{id}Fetch one verification. Poll this until code is non-null and status is received.
curl https://api.fetchsms.com/v1/verifications/9f3e1c2a-… \
-H "Authorization: Bearer YOUR_API_KEY"{ "id": "9f3e1c2a-…", "status": "received", "code": "482910", … }/v1/verifications?tab=activeList your verifications. tab is active (default) or history.
curl "https://api.fetchsms.com/v1/verifications?tab=active" \
-H "Authorization: Bearer YOUR_API_KEY"/v1/verifications/{id}/cancelCancel 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"Rentals (long-term)
A rental gives you an exclusive number for 1–365 days that works for any service and receives unlimited codes for the whole term — a single flat-priced product (priced per term, not per service). A rental that ends without ever receiving a code is refunded.
/v1/rentals| service | integer or string · required | Long-term product id 1. The slug "unlimited-services" is accepted for compatibility. |
| days | integer · required | Term: 1, 7, 30, 90, or 365. |
| area_code | string | Optional 3-digit US area code (+$0.10). |
curl https://api.fetchsms.com/v1/rentals \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"service": 1, "days": 30}'{
"id": "1a2b3c4d-…",
"ref": "r_K9m2Lp",
"service": "unlimited-services",
"service_name": "Unlimited Services",
"number": "(415) 555-0142",
"duration_days": 30,
"last_code": null,
"status": "waiting",
"cost_cents": 1200,
"created_at": "2026-06-17T22:14:05Z",
"expires_at": "2026-07-17T22:14:05Z"
}Errors: 402 insufficient balance, 404 unknown service, 409 out of stock, 422 unsupported duration.
/v1/rentals/{id}Fetch one rental. last_code holds the most recent code received on the number.
curl https://api.fetchsms.com/v1/rentals/1a2b3c4d-… \
-H "Authorization: Bearer YOUR_API_KEY"/v1/rentals/{id}/messagesEvery SMS received on the rental number, newest first.
curl https://api.fetchsms.com/v1/rentals/1a2b3c4d-…/messages \
-H "Authorization: Bearer YOUR_API_KEY"[
{
"id": "…",
"sender": "WhatsApp",
"body": "Your WhatsApp code: 821-193",
"code": "821-193",
"received_at": "2026-06-17T22:31:10Z"
}
]/v1/rentals?tab=activeList your rentals. tab is active (default) or history.
curl "https://api.fetchsms.com/v1/rentals?tab=active" \
-H "Authorization: Bearer YOUR_API_KEY"/v1/rentals/{id}/cancelCancel a rental that has not received a code yet (refunded). Otherwise returns 409.
curl -X POST https://api.fetchsms.com/v1/rentals/1a2b3c4d-…/cancel \
-H "Authorization: Bearer YOUR_API_KEY"Wallet
Purchases are paid from your prepaid wallet balance. API-key requests can spend from that balance through verification and rental purchases, but wallet balance, deposits, and ledger history are dashboard-only and do not accept API keys.
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.
| sms.received | event | A code/SMS arrived on a verification or rental number. |
| rental.expired | event | A long-term rental reached the end of its term. |
Delivery headers:
| X-FetchSMS-Event | string | The event type, e.g. "sms.received". |
| X-FetchSMS-Signature | string | HMAC-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).
| ID | Slug | Service | Verification price |
|---|---|---|---|
| Loading catalog… | |||