Service 03 / OTP API
OTP over SMS
or WhatsApp.
One flow for SMS and WhatsApp. Send a code, verify what the user typed, and track delivery without ever storing the code in plaintext.
Verification flow
Send, verify, track.
The system generates a code, stores its hash, holds the charge, then queues the message. When the user submits the code, the verify endpoint checks the newest code that is still valid.
- 01
Send a code
Pick SMS or WhatsApp. The template is optional; leave it out and the default one is used.
- 02
Verify
Send the number and the code. Every wrong code adds an attempt.
- 03
Track
Use the request ID to check status and the expiry time.
curl -s -X POST "$NOTIF_API_URL/api/v1/otp/sms/send" \ -H "Authorization: Bearer $NOTIF_TOKEN" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: login-2026-11-07-001" \ -d '{ "recipient": "081234567890", "template": "Your notif code: {otp}. Valid for 5 minutes.", "ttl": 300 }'curl -s -X POST "$NOTIF_API_URL/api/v1/otp/verify" \ -H "Authorization: Bearer $NOTIF_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "recipient": "081234567890", "code": "123456", "channel": "sms" }'curl -s "$NOTIF_API_URL/api/v1/otp/01JBCDEFGHJKMNPQRSTVWXYZ" \ -H "Authorization: Bearer $NOTIF_TOKEN" \ -H "Accept: application/json"How it works
Short codes, strict rules.
OTP security is not just about code length. Expiry, attempt limits, and how the hash is stored decide whether a code can still be trusted.
- HMAC hash
- Codes are stored as an HMAC hash keyed to your application, never as plaintext.
- Expiry
- 60 to 900 seconds. Defaults to 300.
- Attempts
- 5 tries at most. After that the request is marked failed.
- Cooldown
- 60 seconds between requests for the same number and channel.
- Number
- Responses show the number with its digits masked.
- Idempotency
- Reusing a key returns the request you already created.
Endpoints
Four endpoints, one flow.
Token scopes are enforced per channel. A token with otp-sms:create cannot send WhatsApp OTPs on its own. Split permissions to match what each app actually needs.
- POST
/api/v1/otp/sms/sendCreates a new OTP request on the SMS channel.
otp-sms:create - POST
/api/v1/otp/whatsapp/sendCreates a new OTP request on the WhatsApp channel.
otp-whatsapp:create - POST
/api/v1/otp/verifyVerifies the latest code for a number and channel.
otp-sms:verify | otp-whatsapp:verify - GET
/api/v1/otp/{id}Returns the current status of a single OTP request.
otp-sms:read | otp-whatsapp:read
Limits and pricing
The limits and costs that shape verification.
Scroll the table sideways to see the other columns.
| Item | Value | Notes |
|---|---|---|
| Expiry | 60 to 900 seconds | Defaults to 300 seconds. Anything outside this range is rejected. |
| Template length | 255 characters | Must contain the {otp} or {code} placeholder. |
| Verification attempts | 5 tries | Each wrong code adds an attempt. After the fifth, the code fails. |
| Request cooldown | 60 seconds | At most 5 requests per hour for the same number and channel. |
| API rate limit | 120 / minute | Counted per token and per account. |
| Pricing | Per request | The charge is held when the request is created and settled once the gateway accepts the message. |
Questions
Before you send the first code.
Can users ask for a new code?
Yes, after the 60-second cooldown. The same number and channel get at most 5 requests per hour. Reuse the same Idempotency-Key when retrying a request that failed on a dropped connection.
How long is a code valid?
You decide, between 60 and 900 seconds. Leave it empty and the system uses 300. The create response includes expires_at in ISO 8601 format.
What happens after 5 failed attempts?
The OTP request is marked failed and the code can no longer be verified. The user has to request a new one once the cooldown passes.
Are codes stored in the database?
Only as an HMAC hash keyed to your application, never in plaintext. The raw code goes to the recipient and nowhere else.
Can I change the message template?
Yes, up to 255 characters, and it must include {otp} or {code}. If you leave it blank, the default template is used.
Is there a sandbox before production?
Yes. The OTP page in the dashboard has a sandbox tab where you can try sending and verifying without writing any integration code first.
Other services
OTP verification without building the service yourself.
Create a token with the OTP scopes, send your first request, then verify codes from your app.