SMS verification at user sign-up: OTP without holes
· 3 min read
A verified phone number is worth its weight in gold: it is account recovery, second factor and bot filter, all in one. Verifying it looks trivial —send a code and compare it— and that is why almost every home-made implementation makes the same three mistakes. We describe them, because our API exists so that you do not have to solve them yourself.
The three classic mistakes
- Storing the code in plain text. The code ends up in the database, in the logs or in the dashboard's message history — and anyone who sees any of the three can verify someone else's phone. On our platform the code is never stored in plain text: only its cryptographic fingerprint, and the text of the SMS is redacted in the history.
- Codes that never expire. Without expiry or a limit on attempts, a 6-digit code can be brute-forced. Ours expire and lock after a few failed attempts.
- Ignoring traffic fraud. SMS pumping —bots requesting thousands of verifications towards ranges with inflated rates— comes out of your pocket. Limits by origin and control by destination, built in.
How it is integrated
Two calls: verify/start with the number, verify/check with the code the
user typed. A wrong code returns the status invalid — not an HTTP error — so
that your form can tell “they made a mistake” apart from “something failed”.
Idempotency on sending: if your server retries, neither the SMS nor the charge
is duplicated.
Does the user prefer WhatsApp? The same flow works on both channels, and your code decides to retry on the other one with one more call.
The detail almost nobody looks at: the receipt
An OTP that “was sent” but did not arrive is a user lost at the worst moment: sign-up. In Spain the receipt confirms delivery to the handset; in other destinations only that the network accepted it — we have it measured country by country and we warn you before sending, not after invoicing.
API documentation · Price per country · Test mode when you create your account, no card required.
The cost of getting it wrong, in numbers you will have seen
A sign-up form that loses users at the code step is money thrown away on acquisition: every click that got that far has already been paid for. The three typical leaks and their remedy:
“The code is not arriving.” Sometimes it is coverage; often it is a receipt that lied. A visible resend after a few seconds —with a minimum window between sendings so as not to burn balance— and a retry on the other channel solve most cases.
“I typed it wrong.” A clear invalid response and a field ready to try
again, without reloading the page or invalidating the remaining code until the
attempts run out.
“It arrived late.” A short expiry is security, but the user has to see it: a visible countdown stops them typing a code that is already dead.
All of this comes solved in the API: expiry, attempts, resend windows and statuses your interface can turn into useful messages.