1
Start a verification
POST /api/v1/verify with the user’s phone number. Torpedo sends the code and returns a
verification id.2
Check the code
POST /api/v1/verify/{id}/check with the code the user typed. valid: true means the number
is verified.Requirements
- A WhatsApp balance in your workspace. Top it up from WhatsApp → Buy credits in the dashboard. See Pricing and balance.
- For SMS fallback: SMS credits, and a Mozambican mobile number as the recipient.
Start a verification
202 Accepted. The code is sent in the background:
Request fields
Pass an
Idempotency-Key header to make retries safe. A repeated request with the same key returns
the original verification instead of sending a new code.
One pending verification per number
A number can only have onepending verification at a time. Starting another one returns 409
with the existing ID in the message:
Check the code
200 while the verification is pending:
By default a verification allows 5 guesses. You can lower this to 3 or 4 in WhatsApp → Settings.
Checking a verification that has already ended returns
410 Gone:
Torpedo stores only a hash of the code. Once a verification ends, the code is deleted and can’t be
recovered.
Code lifetime and verification statuses
A code expires after the time set by the template, which is 5 minutes for Torpedo’s shared templates.expiresAt on the verification tells you exactly when.
Each send is recorded in
attempts, with its own status (queued, sent, delivered or
failed) and a trigger of initial, resend or fallback.
Resend the code
If the message didn’t arrive, send the same code again on the same verification:channel is optional. Omit it to resend on the verification’s channel, or set it to switch, for
example from WhatsApp to SMS. The response is 202 with the updated verification.
- You can resend once 30 seconds after the last send.
resendAvailableAttells you when. - A verification can be sent at most 5 times in total, including the first send and any fallback.
429 with a Retry-After header (PREMATURE_RETRY or MAX_SEND_ATTEMPTS).
Resending doesn’t extend expiresAt.
SMS fallback
With"fallback": "sms", Torpedo sends the same code by SMS when the WhatsApp message fails, for
example because the number isn’t on WhatsApp. The fallback is only triggered by a failure, never by
a timer, and happens at most once per verification.
fallback. It needs SMS credits and only reaches Mozambican mobile numbers. The SMS is
sent from your default sender ID, or the one chosen in Verify
settings.
When a fallback is sent, you receive a verification.fallback webhook.
SMS autofill
Phones can fill in a code from an SMS automatically when the message is formatted for it. Set these in WhatsApp → Settings and Torpedo formats every Verify SMS to match:
With both set, a Portuguese SMS looks like this:
Bring your own code
If your system already generates codes, pass yours incode. Torpedo delivers it, and you can either
check it with /check as usual, or check it yourself and tell Torpedo the result:
approved so your conversion stats stay accurate. Only
verifications started with your own code can be reported.
Starting a verification with your own code while another one is pending for the same number
cancels the old one instead of returning 409, since your system has already replaced the old code.
Cancel a verification
canceled and its code stops working. Cancel when the user abandons the
flow or changes their number, so you can start a fresh verification right away.
Get and list verifications
status, channel, to, limit and cursor, and returns { data, meta } with
the same cursor pagination as the other list endpoints.
Putting it together
A typical sign-up or login screen:- Start. When the user submits their number, call
POST /api/v1/verifyfrom your server with their number, yourclientRefand theirip. Store the returnedidin their session. Never send the code or the verification to the browser. - Ask for the code. Show a code input. Disable the “Send again” button until
resendAvailableAt, then call/resendwhen the user presses it. Offer “Send by SMS instead” as a resend with"channel": "sms"for Mozambican numbers. - Check. Call
/checkwith what the user typed. Onvalid: true, mark the number as verified. Onvalid: false, show how manyattemptsRemainingare left. - Handle the ends.
409 VERIFICATION_PENDINGon start: the user already has a code on its way. Keep the existing verification and show the code input, or cancel it and start again if they changed numbers.410on check or resend: the verification ended (expired, too many guesses or canceled). Ask the user to request a new code.429: wait forRetry-Afterbefore trying again, and tell the user how long.
Webhooks
Subscribe a webhook to these events to follow a verification without polling:
See the payload fields for each event.
Testing
Create a test API key in the dashboard to try Verify without paying for messages. With a test key,to must be either your own verified phone number or one of these sandbox numbers:
Sandbox numbers send nothing and are free. The code is always
000000, and all webhooks fire as
they would for a real number.
Each workspace gets 20 test verifications, sandbox ones included. After that, a test key can still
use sandbox numbers, but sending to your own phone number needs a live key.
Rate limits
To stop attackers from pumping messages to a number (SMS pumping and toll fraud), Verify limits how often a number can receive codes, on top of the API rate limit:- At most 5 starts per hour per number by default (configurable from 1 to 20 in WhatsApp → Settings), and twice that per day.
- At most 3 starts in 10 minutes per number, whatever your setting.
- At most 20 starts in 10 minutes per end-user IP, when you pass
ip. - At most 15 wrong guesses per hour per number, across all its verifications.
429 with code RATE_LIMITED and a Retry-After header.
You can also restrict which countries can receive codes in WhatsApp → Settings. A number from a
country that isn’t allowed returns 422 with code COUNTRY_NOT_ALLOWED.
Templates and your own number
WhatsApp only allows codes to be sent with an approved authentication template. Torpedo provides approved templates in Portuguese and English on its shared sender, so you can start right away. To send codes from your own business number and name, connect your number in WhatsApp in the dashboard (WhatsApp → Number) and create authentication templates under WhatsApp → Templates. Once your number is connected and a template for the verification’slocale is approved, Verify uses it instead of the
shared sender. Pass template to pick a specific approved template by name.
If no approved template matches, the start returns 422 with code TEMPLATE_UNAVAILABLE.
Pricing and balance
WhatsApp messages are charged from your workspace’s WhatsApp balance, which is separate from SMS credits. The price depends on the recipient’s country and follows Meta’s rate card. See the current rates on the pricing page, or fetch them without an API key:- The balance is held in MZN or USD, chosen on your first top-up. Top up with M-Pesa or a card from WhatsApp → Buy credits.
- Each send is charged when the verification starts or the code is resent. A WhatsApp message that fails is refunded, since WhatsApp only bills delivered authentication messages.
- An SMS fallback or SMS-channel verification uses one SMS credit.
- Torpedo emails you when your WhatsApp balance runs low. Set the threshold in WhatsApp → Settings.
GET /api/v1/workspace/usage with your API key:
data.usage.whatsappBalance is the balance as a decimal string, for example "412.5000", and
data.usage.whatsappBalanceCurrency is MZN, USD, or null before your first top-up.
When the balance can’t cover a message, the start returns 402: