SMSAPI
— Verification

Build a complete OTP verification flow

A verification flow is more than one OTP — it's send, entry, verify, and the resends, expiries, and fallbacks around them. We hold the state, so your flow is a couple of API calls rather than a state machine you maintain and secure.

The states a flow moves through

A verification starts when you call send: we generate the code, deliver it, and return a verification_id for this attempt. The user enters the code, you call verify with the ID and their input, and you get back verified, mismatched with attempts remaining, or expired. Those few states are the whole flow, and none of the code lives in your database.

Resends are part of it. A user who didn't get the code asks again, and a resend reuses the same verification rather than starting a new one, so the attempt counter stays meaningful and the first code isn't orphaned. You set how soon a resend is allowed and how many a number gets.

Fallback covers the SMS that doesn't arrive: after a window you set, the same code is read out on a voice call, with the verification_id unchanged so your verify call doesn't branch. On Android, auto-read can fill the code from the SMS before the user does anything at all.

Expiry and abuse caps close the loop. A code lives for the time-to-live you set, a number can request only so many codes in a window, and a code can be guessed only so many times before it locks. Together those keep a flow smooth for real users and useless to an attacker.

What’s included

— Send & verify

Two calls

Send returns a verification_id; verify checks the user's input against it.

— Resend

Reuses the attempt

A resend keeps the same verification so counters stay meaningful.

— Fallback

Voice when SMS fails

The same code is read out on a call, with no change to your verify call.

— Auto-read

Android auto-fill

The code fills itself via SMS Retriever before the user types.

— Expiry

TTL you set

Codes expire on a time-to-live so a leaked code is short-lived.

— Abuse

Attempt and rate caps

Limit guesses per code and codes per number to blunt abuse.

Frequently asked

What states does a verification move through?

Sent, then verified, mismatched, or expired. Send returns a verification_id; verify returns the result against it, with attempts remaining on a mismatch. A resend reuses the same verification. You branch on those states rather than tracking codes yourself, and the code is never returned to you.

How should I handle a resend?

Call send again for the same user; we reuse the verification rather than issuing a parallel one, so the first code isn't orphaned and your attempt counter stays accurate. You control how soon a resend is allowed and how many a number can request before it's rate-limited.

What happens if the SMS never arrives?

Enable voice fallback: after a window you set, the same code is placed as a short voice call that reads it out. The verification_id doesn't change, so your verify call is identical regardless of whether SMS or voice delivered the code.

Does this work on web as well as mobile apps?

Yes. The send-and-verify model is channel- and platform-agnostic. Auto-read is an Android convenience; on web and iOS the user enters the code, and the same verify call confirms it. The flow and the API are the same everywhere.

Start building.