Getting started with the OTP API
Everything the dashboard does, you can automate: buy a number, poll for the code, and handle refunds over a clean REST API with idempotency built in.
The dashboard is the fastest way to receive a single code, but the moment you need to verify accounts at scale — onboarding flows, automated testing, batch registrations — you will want the API. It exposes the same primitives the dashboard uses: browse the catalog, buy a number under a lock, poll for the code, and rely on automatic refunds when a route misses. This is the shape of a clean integration.
Authentication
Every request authenticates with an API key you create in the dashboard. The key is sent as a bearer token in the Authorization header. Treat it like a password: keep it server-side, never ship it in a browser bundle or mobile app, and rotate it if you suspect exposure. Only a hash of your key is ever stored, so a leaked key cannot be recovered from us — it can only be revoked and replaced.
Authorization: Bearer sk_live_your_key_hereKeys carry rate limits, so a runaway loop degrades gracefully into 429 responses rather than draining your wallet. Back off and retry on a 429 rather than hammering the endpoint; the limit exists to protect your balance as much as our infrastructure.
The core flow
A verification is three logical steps, each a single call. The whole cycle typically completes in well under a minute.
- Buy: request a number for a service-and-country pair. The response gives you an activation id and the leased phone number. Your wallet is charged atomically as part of this call.
- Poll: check the activation by its id until the code arrives or the lease times out. When the SMS lands, the parsed code and the full message body are returned.
- Resolve: mark the activation done once you have used the code, or let it time out — in which case you are refunded automatically, no extra call required.
That is the entire happy path: one call to buy, a short poll loop, and an optional completion. There is no session to manage, no socket to keep open, and no manual refund accounting to reconcile at the end.
Idempotency: the detail that saves you
Networks are unreliable, and the buy call moves money. If your request times out, did the purchase happen or not? Retrying blindly risks buying two numbers and paying twice. Idempotency keys remove the guesswork entirely.
Attach a unique idempotency key to each buy request. If you send the same key twice — because your first attempt timed out and you retried — the server recognises it and returns the original result instead of performing a second purchase. Generate a fresh key per logical purchase (a UUID works well), store it alongside your own record of the attempt, and reuse it on every retry of that same attempt.
- One key per intended purchase — never reuse a key across two different numbers you actually want.
- Persist the key before you send the request, so a crash mid-flight still lets you retry safely.
- Retry with the same key on timeouts and 5xx responses; you will get the original outcome, not a duplicate charge.
Polling politely
The poll step is a loop, and loops can misbehave. Poll at a sensible interval — every few seconds is plenty — rather than in a tight spin. The code cannot arrive faster than the destination service sends it, so sub-second polling only burns rate limit for no gain.
Respect the lease timeout as your loop's exit condition. When the activation reports a timed-out or refunded state, stop polling and, if you still need a code, start a fresh activation on a different country. Building that fallback into your loop is what turns a fragile script into a dependable pipeline.
Handling money correctly
Balances are tracked with integer precision internally, so you never lose fractions of a cent to floating-point drift. On your side, keep the same discipline: treat amounts as integers in the smallest unit, and reconcile against the transaction history the API exposes rather than trying to predict balances yourself. Refunds from missed codes land back in your wallet automatically, and they will show up in that history as first-class entries.
A sensible first integration
Start small. Wire up the buy-poll-resolve loop for a single service and country, with an idempotency key on the buy and a timeout-aware poll. Confirm you can receive one code end to end, then add a retry-on-different-country fallback, then parallelise across many activations once the single path is rock solid.
The full endpoint reference — request and response shapes, error codes, and rate-limit headers — lives in the API docs. But the mental model above is the whole game: authenticate with a bearer key, buy idempotently, poll politely, and let the automatic refund handle the misses. Get those four habits right and everything else is detail.