Start with the exact OTP attempt
When a user says an OTP SMS code did not arrive, avoid debugging the account in general. Debug the exact attempt: the phone number used, the timestamp, the template, the sender identity, the provider message ID, and every delivery event received after the API request.
The first useful split is whether the failure happened before the SMS platform accepted the message, after acceptance but before a final delivery signal, or inside the product verification flow after the message arrived. Those are different problems. A rejected API request points toward formatting, credentials, sender setup, account balance, or policy controls. An accepted request with no final receipt points toward routing, carrier handling, country behavior, handset availability, or delayed callbacks. A delivered message with failed verification points back to code expiry, resend rules, user entry, or stale attempts.
An OTP failure is usually a message lifecycle problem, a product-state problem, or an abuse-control problem. Treat it as evidence, not as a mystery.
- Confirm the phone number was normalized and attached to the right country.
- Check whether the SMS API accepted, queued, or rejected the send request.
- Compare the code expiry window against the delivery timeline.
- Separate delivery failure from code-entry failure.
- Preserve raw webhook events before mapping them into support-friendly states.
Find the failed OTP step
| What you see | What it means | Check next | Safe next action |
|---|---|---|---|
| The send request failed | The SMS platform did not accept the message. | Check the normalized phone number, credentials, account balance, sender permission, request validation error, and provider response. | Correct the rejected request before allowing another attempt. Do not resend the same invalid request. |
| The message was rejected | The provider or carrier refused the message after the request reached the messaging service. | Check the rejection code, destination country, sender approval, route, template, and policy reason. | Use an approved sender or route. Offer another verified method when the destination cannot receive the SMS. |
| The code is delayed or has no final delivery status | The message is still moving through the provider or carrier path, or the final delivery report is missing. | Compare API acceptance, sent, delivered, failed, and callback times for the same provider message ID. | Wait for the documented delivery window, then offer a controlled resend or another verified method without creating several active codes. |
| The code expired before use | The active verification attempt ended before the user completed it. | Compare the code expiry time with delivery time, resend time, and the attempt the user submitted. | Create one fresh attempt after the cooldown and invalidate older codes so the user has one valid code. |
| The message was delivered but verification failed | SMS delivery succeeded, but the submitted code does not match the current verification attempt. | Check whether the user entered an older code, exceeded the attempt limit, or submitted after a resend replaced the active code. | Explain which attempt is active. After the cooldown, issue one new code or offer another verified method. |
Do not start by increasing resend volume. Resends help only when the next attempt uses a valid number, an available route, a supported sender identity, and a code window the user can still complete. If every resend creates a new active code, support may see several pending attempts while the user is trying the wrong value. Treat resend as a product action with cooldowns, idempotency, and clear state, not as a blind fix for every delivery complaint.
What support needs to see
A useful support view should show one OTP attempt as a timeline. That includes the recipient, destination country, sender identity, template version, provider message ID, current status, raw callbacks, error category, retry count, and the next recommended action.
The timeline should also separate user-facing status from internal evidence. A support agent can safely say that a message was submitted, delayed, reported delivered, failed, or expired. They should not need to interpret raw carrier codes during a live chat. Engineering still needs the raw event details, because those details are what make a provider escalation useful when a country, sender, or carrier pattern repeats.
- Find the latest OTP attempt for the user and destination number.
- Check whether the request was accepted by the messaging platform.
- Wait for or inspect delivery receipts before promising delivery.
- Confirm the code did not expire before the delivery signal arrived.
- Escalate with message ID, country, sender identity, timestamps, and raw event evidence.
Make OTP attempts traceable
Use Notilify to connect OTP attempts, delivery events, sender identity, and support timelines.
Start sending