Hashed at rest
Plaintext OTP codes are never stored. Verification compares against a hash so a database leak does not expose active codes.

OTP
Login codes, payment PINs, and account verification for Ghana numbers. POST /v1/verify/send dispatches the SMS; POST /v1/verify/check validates the code your user typed — with hashed storage, cooldown, and a delivery report you can open later.
API
curl -X POST "https://api.taysend.com/v1/verify/send" \
-H "Authorization: Bearer sms_test_..." \
-H "Content-Type: application/json" \
-d '{ "to": "+233200000001", "locale": "en" }'Security
Plaintext OTP codes are never stored. Verification compares against a hash so a database leak does not expose active codes.
Per-phone send cooldown, max verification attempts, and send-rate limits are enforced server-side — not left to client logic.
sms_test_ keys use simulated numbers. You can exercise the full send-and-check flow without delivering to a real phone.
OTP traffic routes separately from bulk campaigns so a large marketing blast does not delay login codes.
POST /v1/verify/check returns verified, expired, invalid, or max attempts — not a generic success when the code is wrong.
The same message id and DLR model applies. Open GET /v1/messages/:id to see whether the OTP SMS was delivered, failed, or expired.
Compare
OTP is for one-to-one verification with short-lived codes. Bulk SMS is for campaigns to many recipients via lists or the recipients array. They use different queues so neither starves the other. For marketing blasts, see bulk SMS.
Explore
Each page answers a different question. They are not copies of this one.
FAQ
If something here is product behaviour, it matches the dashboard and the API.
POST /v1/verify/send to dispatch a code, POST /v1/verify/check to validate it. Both require Bearer authentication.
Yes. TEST keys send to simulated numbers only. The verify/check flow works the same way without touching a real handset.
LIVE OTP requires an approved alphanumeric sender ID (3–11 characters). TEST uses the sandbox sender TAYSEND.
No. Never log plaintext codes. Use the check endpoint and handle expired or max-attempt responses in your UI.