Documentation
POST /otp/resend
Advance the same verification to the next enabled channel after a cooldown, so a code that did not get through gets another route.
Advance the same OTP to the next enabled channel after a cooldown. The response has
the same shape as send, with the new channel. Once your order is
exhausted, a resend repeats the last usable channel rather than refusing. Pass an
optional channel to move the OTP onto a specific channel instead of the next one:
a fresh code is delivered there. You do not re-send client_ip: the resend is
evaluated with the IP declared on the original send.
curl -X POST https://api.otp.com/api/v1/otp/resend \
-H "Authorization: Bearer otp_live_•••" \
-H "Content-Type: application/json" \
-d '{"otp_id":"9f3c1b2a-…"}'
Request body
| Field | Type | Required | Description |
|---|---|---|---|
otp_id | string | yes | The id of the verification to advance. |
channel | string | no | Move the OTP onto this exact channel (sms, whatsapp, telegram, email) instead of advancing to the next one. Must be enabled for your app and the recipient. |
Verify by SMS when the user has no WhatsApp
In the two WhatsApp link modes the user has to open the action_url to finish, so a
user without WhatsApp (or one whose code does not arrive) cannot complete it there.
Resend with {"otp_id":"…","channel":"sms"} to move that pending OTP onto SMS: it
delivers a fresh code and the response comes back with action_url: null, so you
continue with the normal verify step. Naming the channel is what
makes this work: a plain resend on an OTP that is already on a wa.me link just
re-returns the same link. See WhatsApp verification.
Response
{
"otp_id": "9f3c1b2a-…",
"status": "pending",
"channel": "whatsapp",
"masked_recipient": "+1****71",
"action_url": "https://wa.me/13845555555?text=Verify%20me%3A%20aB3xZ-…",
"completion": "code"
}
channel reflects the next channel in your order. On SMS, email, and Telegram the
same code is re-issued; a fresh code is not generated. WhatsApp under Template
behaves the same way. In the two link modes a plain resend skips WhatsApp unless it
is first in your order; name it with {"channel":"whatsapp"} to move the OTP onto
it anyway, and the response returns an action_url for your app to show. A later
plain resend re-returns that same link, so to move the OTP off WhatsApp, name the
channel you want.
Common errors
| Status | Type | When |
|---|---|---|
409 | ResendNotAllowedError | The OTP’s send attempts are spent, or no enabled channel is left for the recipient. |
429 | ResendCooldownError | Resend attempted within the cooldown window. Retry-After carries the seconds left. |
See How verification works for the fallback model, or Error codes for the full list.