Temporary verification numbers, captured by API
Order a number for a specific service and country, receive the one-time password as a signed webhook or by polling, and get a full automatic refund if no SMS ever arrives.
{
"id": "act_9f2c41d0b7e3a6158c24",
"object": "activation",
"status": "received",
"service": "telegram",
"country": "us",
"phone_number": "+15550142231",
"code": "482913",
"sms_text": "Telegram code: 482913",
"price": 0.2,
"created_at": 1793318400,
"expires_at": 1793319600,
"received_at": 1793318447
}
Every activation ends in a code or a refund
An activation is a single-use reservation of a number for one service. Its status moves through a small, well-defined state machine.
Debit on order
The current price for the service and country is debited when the activation is created. If the order fails upstream, it is refunded immediately.
Retry codes
If the service sends another SMS while the activation is received, the code is updated so you always read the latest one.
Explicit completion
Call POST /v1/activations/{id}/complete once you have used the code. Only activations that received a code can be completed.
Polling or webhooks — your choice
Both modes read from the same activation record. Many teams start by polling and move to webhooks in production.
| Polling | Webhooks | |
|---|---|---|
| How it works | Call GET /v1/activations/{id} until status changes | We POST activation.sms_received to your HTTPS endpoint |
| Latency | Bounded by your poll interval | Pushed as soon as the code is captured |
| Rate-limit usage | Each poll counts toward your 300 requests/min | Deliveries do not count toward your API limit |
| Infrastructure | None — works from scripts, CI jobs and notebooks | A publicly reachable HTTPS endpoint |
| Security | Bearer API key over TLS | HMAC-SHA256 signature with timestamp per delivery |
| Lifecycle events | Read status on each call | activation.sms_received, activation.expired, activation.cancelled |
| Best for | Prototypes, CI jobs, low volume | Production systems and higher volume |
Guides: Webhook-based OTP capture · Measuring OTP delivery latency · Developer console
Order, wait, read the code
A complete polling loop in Python. Swap the loop for a webhook handler when you are ready — the activation object is identical.
max_pricerejects the order with409if the live price is higher402tells you to top up before retrying- Cancel with
POST /v1/activations/{id}/cancelafter the short cooldown
import time, requests
API = "https://otproute.com/api/v1"
H = {"Authorization": "Bearer or_live_…"}
act = requests.post(f"{API}/activations", headers=H,
json={"service": "telegram", "country": "us", "max_price": 0.50}).json()
# use act["phone_number"] in the flow under test
while True:
a = requests.get(f"{API}/activations/{act['id']}", headers=H).json()
if a["status"] == "received":
print("OTP:", a["code"])
requests.post(f"{API}/activations/{a['id']}/complete", headers=H)
break
if a["status"] in ("expired", "cancelled"):
break # refunded automatically
time.sleep(5)
From $0.20 per code — only if it arrives
Pay as you go from your USD wallet, with no plans and no monthly fee. If no code arrives within the 20-minute window, the full amount goes back to your wallet automatically.
Live cost
Each service and country has its own price, driven by live availability. See it in the dashboard or query it any time with GET /api/v1/prices.
Pay only for codes
The price is held from your wallet when you order. No code within 20 minutes, or you cancel? The full amount is returned automatically.
Price ceiling
Pass max_price to cap what a single activation may cost. Orders above it are rejected instead of debited.
Refunds are automatic, not negotiated
- Expired: no SMS within the activation window — the full price returns to your wallet.
- Cancelled: you cancel a pending activation after the provider cooldown — full refund.
- Failed to order: the upstream route could not issue a number — refunded immediately.
- Received: once a code is delivered, the activation is consumed and not refundable.
Each activation is refunded at most once and recorded in your wallet ledger. See the Refund Policy.
Errors you should handle
| HTTP | Code | Meaning |
|---|---|---|
| 401 | unauthorized | Missing or invalid API key. |
| 402 | insufficient_balance | Wallet cannot cover the current price. Top up and retry. |
| 404 | not_found | Service unavailable in that country right now, or unknown activation ID. |
| 409 | conflict | Price exceeds max_price, the activation is already closed, or the cancel cooldown has not elapsed. |
| 423 | account_locked | The account is locked. Contact support. |
| 429 | rate_limited | More than 300 requests per minute. Honour Retry-After. |
{ "error": { "code": "insufficient_balance",
"message": "Insufficient balance: this activation costs $0.20" } }
OTP Gateway questions
How long does an activation stay open?
expires_at on the activation. If no SMS arrives by then, the activation becomes expired and is refunded in full.Can I cancel an activation straight away?
cancelable_after. Cancelling earlier returns 409 with the remaining seconds. A cancelled activation that never received a code is fully refunded.Why does the price differ between services and countries?
GET /api/v1/prices to read current prices and max_price to cap them per order.Do I need webhooks?
GET /v1/activations/{id} works everywhere. Webhooks deliver codes faster and save API requests, so they are recommended for production workloads.Can I test without spending money?
Capture your first OTP today
Pay as you go with no monthly fee. Pay only for activations that deliver a code.