# SMS verification API for developers

Source: https://tempsmsverify.com/api-docs · Last updated: 2026-10-23

The TempSMSVerify SMS verification API lets you buy temporary numbers, read OTP codes and cancel unused numbers from your own code. It comes in two flavors that share one balance and the same billing rule, pay only if the code arrives: a JSON REST API under /api/v1 and an SMS-Activate-compatible endpoint for existing bots and tools.

## Does TempSMSVerify have an SMS verification API?

Yes. TempSMSVerify offers a REST API at https://tempsmsverify.com/api/v1 and an SMS-Activate-compatible endpoint at /api/stubs/handler_api.php. Both use an API key, available after your first top-up. Buying a number freezes its price; you are charged only when the SMS arrives, and cancelled or expired numbers are refunded automatically.

## Key facts

| Fact | Detail |
| --- | --- |
| REST base URL | https://tempsmsverify.com/api/v1 |
| SMS-Activate-compatible endpoint | https://tempsmsverify.com/api/stubs/handler_api.php (GET or POST) |
| Authentication | X-Api-Key header, Authorization: Bearer, or api_key query parameter |
| API access | API key available after your first top-up; one active key per account |
| Billing | Price frozen on purchase, charged only when the SMS arrives, refunded otherwise |
| Number reserved for | up to 20 minutes |
| Purchase limit | 500 purchases per minute per account (and per IP on REST) |
| Recommended polling | Every 3 to 5 seconds |

## How does the TempSMSVerify API work?

Every activation follows the same lifecycle. You request a number for a service (and optionally a country). The price is frozen in your balance and the order starts as PENDING. You enter the number in the target app, then poll the order. When the SMS arrives, the order switches to RECEIVED, the code is returned and the frozen amount is charged. You then finish the order, or cancel it if nothing arrived.

Both APIs run on the same business logic as the website: same catalog, same prices, same balance and the same automatic refunds. Use the REST API for new integrations, and the SMS-Activate-compatible endpoint when you already have software written for that protocol.

## How do I get and use an API key?

API access unlocks after your first confirmed top-up (minimum $5). Open the API section of your dashboard and generate a key. The full key is shown only once, at generation; we store only a hash, and the dashboard later shows just its first characters. Each account has one active key: generating a new one revokes the previous key immediately, and you can revoke it at any time.

Send the key in one of three ways, checked in this order: the X-Api-Key header (recommended for REST), an Authorization: Bearer header, or the api_key query parameter (the SMS-Activate style). An invalid or revoked key returns HTTP 401 on REST and BAD_KEY on the compatible endpoint. Treat the key like a password: it can spend your balance.

## What does the SMS-Activate-compatible endpoint support?

Send GET or POST requests to https://tempsmsverify.com/api/stubs/handler_api.php with api_key and action (POST form fields are accepted too). Responses are plain text or JSON and always use HTTP 200, so read the body, not the status code. The service parameter accepts standard protocol codes such as wa or tg, or the service name such as whatsapp. Country is a numeric id in SMS-Activate numbering; omit it or send 0 for the default country, USA (187). The id returned by getNumber is the order id on TempSMSVerify.

| action | Parameters | Success response | Possible errors |
| --- | --- | --- | --- |
| getBalance | none | ACCESS_BALANCE:12.50 | NO_KEY, BAD_KEY |
| getNumber | service, country (optional: numeric id, catalog name or ISO2; 0 = USA), operator (optional), server (optional, 1 or 2) | ACCESS_NUMBER:{id}:{phone} | BAD_SERVICE, WRONG_COUNTRY, WRONG_OPERATOR, NO_BALANCE, NO_NUMBERS, SERVER_ERROR |
| getStatus | id | STATUS_WAIT_CODE, STATUS_OK:{code}, STATUS_WAIT_RETRY:{last code}, STATUS_CANCEL | NO_ACTIVATION |
| setStatus | id, status (1, 3, 6 or 8) | 1: ACCESS_READY; 3: ACCESS_RETRY_GET; 6: ACCESS_ACTIVATION; 8: ACCESS_CANCEL | NO_ACTIVATION, BAD_STATUS, EARLY_CANCEL_DENIED |
| getPrices | country (optional), service (optional), server (optional) | JSON: {"187": {"wa": {"cost": price, "count": stock}}} | {} for an unknown country |
| getNumbersStatus | country (optional), server (optional) | JSON: {"wa_0": stock, "tg_0": stock} | {} for an unknown country |
| getServicesList | none | JSON: {"status": "success", "services": [{"code": "wa", "name": "whatsapp"}]} | none |
| getCountries | none | JSON: {"187": {"id": 187, "eng": "usa", "rus": "usa", "visible": 1, "name": "United States", "iso": "us", "dial_code": "+1"}} for every country with stock (ids above 1000 are TempSMSVerify ids for countries HeroSMS does not number) | none |

## What do the setStatus values do?

setStatus follows the original protocol for the four values that matter in an activation. Any other value returns BAD_STATUS.

| status | Meaning | Response | Notes |
| --- | --- | --- | --- |
| 1 | Ready to receive the SMS | ACCESS_READY | Accepted for compatibility; nothing else changes |
| 3 | Request another SMS on the same number | ACCESS_RETRY_GET | Only after the first code arrived and while the number is active; no extra cost. Otherwise BAD_STATUS |
| 6 | Finish the activation | ACCESS_ACTIVATION | If no SMS ever arrived, the frozen amount is released |
| 8 | Cancel and refund | ACCESS_CANCEL | Only before any SMS arrives. Too early returns EARLY_CANCEL_DENIED (wait about 2 minutes); after an SMS returns BAD_STATUS |

## Which REST v1 endpoints are available?

The REST API lives at https://tempsmsverify.com/api/v1, returns JSON and uses standard HTTP status codes. Authenticate with the X-Api-Key header. Amounts are in your account currency. When you buy, country accepts the catalog name (usa, england, india…), an ISO2 code (us, gb) or the English name; the default is USA. Optional server (1 or 2) picks a line provider; omit it for automatic selection. Service names come from GET /services.

| Method and path | What it does | Notes |
| --- | --- | --- |
| GET /balance | Returns {"balance", "frozen", "currency"} | frozen is the amount held by orders waiting for an SMS |
| GET /services | Catalog: product, price, count (stock), rate, countries_count and selectable countries | Optional ?search= (up to 60 characters), ?server= (1 or 2, default 1), ?country= |
| GET /services/{product}/countries | Every country with an offer for one service: country, name, iso, dial_code, price, count, server, rate3, rate24 and per-server offers[] | Works for any product; optional ?server=; empty list when nothing is in stock |
| POST /orders | Buys a number. Body: {"product": "whatsapp", "country": "usa", "server": 1, "operator": "any"} (server and operator optional) | 201 Created; 400 country/operator not available or cancelling too early, 402 no balance, 404 unknown service, 409 no numbers, 422 invalid body (detail is a list), 429 over 500 per minute, 502 provider unavailable |
| GET /orders | Lists your orders, newest first | ?limit= 1 to 100 (default 50), ?offset= |
| GET /orders/{id} | Order status, synced with the line provider | This is where the SMS shows up; poll every 3 to 5 seconds |
| POST /orders/{id}/finish | Marks the activation as done | Releases the frozen amount if no SMS arrived |
| POST /orders/{id}/cancel | Cancels and refunds | Only before an SMS arrives; may require waiting about 2 minutes (400 if too early). Idempotent: an order already canceled, timed out or banned returns 200 with the order |
| POST /orders/{id}/resend | Requests another SMS on the same number | After the first code, while active, no extra cost; 30 requests per minute |
| POST /orders/{id}/ban | Reports the number as already used or blocked and returns it | Frozen amount released if no SMS was charged; may require waiting about 2 minutes |

## What does an order look like?

Order endpoints return an object with id, phone, product, country, operator, status, price, created_at, expires (UTC timestamps), messages, awaiting_resend, server and provider_order_id (the activation id at the line provider, useful when opening a ticket). Each item in messages has sender, text, code and received_at. When an app sends a message without an isolated code, the full text is still in text.

| REST status | Meaning | getStatus response | Billing |
| --- | --- | --- | --- |
| PENDING | Number issued, waiting for the SMS | STATUS_WAIT_CODE | Price frozen, not charged |
| RECEIVED | SMS arrived; code in messages | STATUS_OK:{code} (STATUS_WAIT_RETRY:{code} while a resend is pending) | Charged |
| FINISHED | Activation closed by you | STATUS_OK:{code}, or STATUS_CANCEL if no SMS ever arrived | Charged only if an SMS arrived |
| CANCELED | Cancelled before any SMS | STATUS_CANCEL | Refunded in full |
| TIMEOUT | Expired without an SMS | STATUS_CANCEL | Refunded automatically |
| BANNED | Reported as used or blocked | STATUS_CANCEL | Refunded if no SMS was charged |

## Are there rate limits, and how are errors returned?

Each account can make up to 500 number purchases per minute across both APIs. On REST, POST /orders is also limited to 500 requests per minute per IP, and resend to 30 per minute; going over returns HTTP 429. On the compatible endpoint, hitting the purchase limit returns NO_NUMBERS. API key generation in the dashboard is limited to 10 per hour.

REST errors use HTTP status codes with a JSON detail field: 400 (invalid request, such as cancelling too early or a country not offered), 401 (missing, invalid or revoked key), 402 (insufficient balance), 404 (unknown service or order), 409 (no numbers in stock), 422 (request body failed validation; detail is a list of field errors), 429 (rate limit: the per-IP limit says "Rate limit exceeded", the per-account limit says "Limit of 500 purchases per minute reached") and 502 (line provider unavailable). A 429 with a Retry-After header can also mean a provider cooldown ("Server 1 is temporarily unavailable"): wait the indicated seconds or retry with the other server. The compatible endpoint always returns HTTP 200 with a text code: NO_KEY, BAD_KEY, BAD_ACTION, BAD_SERVICE, WRONG_COUNTRY, WRONG_OPERATOR, NO_BALANCE, NO_NUMBERS, NO_ACTIVATION, BAD_STATUS, EARLY_CANCEL_DENIED or SERVER_ERROR.

## How do refunds work through the API?

You never have to claim a refund. A purchase only freezes the price. If no SMS arrives within up to 20 minutes, the order times out and the frozen amount returns to your balance automatically. To get it back sooner, cancel with POST /orders/{id}/cancel or setStatus 8 once about 2 minutes have passed. Once an SMS has arrived, the order is charged and can no longer be cancelled; finish it instead.

## What are the API usage rules?

The API has the same purchasing power as your account and the same rules. Use it to verify accounts you own or to test your own products, follow each app's terms, and do not use it for fraud, spam, impersonation or getting around bans. See /acceptable-use. Questions about an integration can go to contact@tempsmsverify.com.

### Check your balance (SMS-Activate-compatible)

```bash
curl "https://tempsmsverify.com/api/stubs/handler_api.php?api_key=$API_KEY&action=getBalance"
# ACCESS_BALANCE:12.50
```

### Get a US number for WhatsApp

```bash
curl "https://tempsmsverify.com/api/stubs/handler_api.php?api_key=$API_KEY&action=getNumber&service=wa&country=187"
# ACCESS_NUMBER:123456:12025550123
```

### Poll for the code

```bash
curl "https://tempsmsverify.com/api/stubs/handler_api.php?api_key=$API_KEY&action=getStatus&id=123456"
# STATUS_WAIT_CODE   (keep polling every 3-5 seconds)
# STATUS_OK:482913   (code received)
```

### Finish or cancel the activation

```bash
# Finish after using the code
curl "https://tempsmsverify.com/api/stubs/handler_api.php?api_key=$API_KEY&action=setStatus&id=123456&status=6"
# ACCESS_ACTIVATION

# Cancel and refund if no SMS arrived
curl "https://tempsmsverify.com/api/stubs/handler_api.php?api_key=$API_KEY&action=setStatus&id=123456&status=8"
# ACCESS_CANCEL  (or EARLY_CANCEL_DENIED: try again in a moment)
```

### REST: buy a number and read the order

```bash
curl -X POST "https://tempsmsverify.com/api/v1/orders" \
  -H "X-Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"product": "whatsapp", "country": "usa"}'

curl "https://tempsmsverify.com/api/v1/orders/123456" -H "X-Api-Key: $API_KEY"
```

### Python: full activation with the REST API

```python
import os
import time
import requests

BASE = "https://tempsmsverify.com/api/v1"
HEADERS = {"X-Api-Key": os.environ["TEMPSMSVERIFY_API_KEY"]}

order = requests.post(f"{BASE}/orders", headers=HEADERS,
                      json={"product": "whatsapp", "country": "usa"}).json()
print("Number:", order["phone"])

deadline = time.time() + 20 * 60
while time.time() < deadline:
    order = requests.get(f"{BASE}/orders/{order['id']}", headers=HEADERS).json()
    if order["messages"]:
        print("Code:", order["messages"][-1]["code"])
        requests.post(f"{BASE}/orders/{order['id']}/finish", headers=HEADERS)
        break
    if order["status"] in ("CANCELED", "TIMEOUT", "BANNED", "FINISHED"):
        print("Closed without a code; the frozen amount was refunded.")
        break
    time.sleep(5)
```

### Node.js: SMS-Activate-compatible flow

```javascript
const BASE = "https://tempsmsverify.com/api/stubs/handler_api.php";
const KEY = process.env.TEMPSMSVERIFY_API_KEY;

async function call(params) {
  const qs = new URLSearchParams({ api_key: KEY, ...params });
  const res = await fetch(BASE + "?" + qs);
  return (await res.text()).trim();
}

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const number = await call({ action: "getNumber", service: "wa", country: "187" });
if (!number.startsWith("ACCESS_NUMBER:")) throw new Error(number);
const [, id, phone] = number.split(":");
console.log("Number:", phone);

for (let i = 0; i < 240; i++) {
  const status = await call({ action: "getStatus", id });
  if (status.startsWith("STATUS_OK:")) {
    console.log("Code:", status.slice("STATUS_OK:".length));
    await call({ action: "setStatus", id, status: "6" });
    break;
  }
  if (status === "STATUS_CANCEL") break;
  await sleep(5000);
}
```

## FAQ

### Is the TempSMSVerify API compatible with SMS-Activate?

Yes, for the core activation flow. TempSMSVerify serves the SMS-Activate handler_api protocol at /api/stubs/handler_api.php with getBalance, getNumber, getStatus, setStatus, getPrices, getNumbersStatus, getServicesList and getCountries. Most tools built for SMS-Activate work after changing the base URL and api_key, and the REST API is there for new projects.

### How do I get an API key?

Make your first top-up of at least $5, then open the API section of your TempSMSVerify dashboard and generate a key. It is shown only once, so store it securely. Each account has one active key; generating a new one revokes the old key immediately, and you can revoke it yourself at any time.

### Am I charged when I request a number through the API?

No. Requesting a number freezes its price in your balance; the charge happens only when the SMS arrives. If the number expires after up to 20 minutes without a code, or you cancel it after about 2 minutes, the frozen amount returns to your balance automatically. GET /balance shows both available and frozen amounts.

### How often should I poll for the SMS code?

Poll every 3 to 5 seconds with GET /api/v1/orders/{id} or the getStatus action. Each check syncs the order with the line provider, so that is where the code appears. Stop polling once you get the code, or when the order is CANCELED, TIMEOUT, BANNED or FINISHED (STATUS_CANCEL on the compatible endpoint).

### What are the API rate limits?

Each account can buy up to 500 numbers per minute across both APIs. On REST, POST /orders is also limited to 500 requests per minute per IP and the resend endpoint to 30 per minute, both returning HTTP 429 when exceeded. On the compatible endpoint, the purchase limit shows up as NO_NUMBERS.

### Which country codes does the compatible endpoint use?

Country ids follow the SMS-Activate numbering. If you omit country or send 0, TempSMSVerify uses the default country, USA, whose id is 187. Call getCountries to list every id available to your account, and getPrices or getNumbersStatus with a country id to see current price and stock.

### Can I get a second code on the same number?

Yes, while the number is still active and after the first code has arrived. Use setStatus with status=3 on the compatible endpoint or POST /api/v1/orders/{id}/resend on REST. There is no extra cost. Until the new SMS arrives, getStatus returns STATUS_WAIT_RETRY with the last code.

### Why does the compatible endpoint always return HTTP 200?

That is how the SMS-Activate protocol works: clients read the response body, not the HTTP status. TempSMSVerify keeps that behavior so existing software works unchanged. Errors arrive as text codes such as BAD_KEY, NO_BALANCE or NO_NUMBERS. The REST API under /api/v1 uses normal HTTP status codes instead.

---
TempSMSVerify · https://tempsmsverify.com
