OTP API
This page covers the concepts shared by all OTP channels. For channel-specific request and response details, see the SMS and WhatsApp guides.
Code Format
Every OTP generated by SecureOTP is a 6-character alphanumeric code drawn from uppercase letters and digits (A–Z, 0–9). Examples: A3K9PZ, B72XQ1, 0WLMR5.
The format is intentionally case-insensitive and avoids easily confused characters, making it safe to dictate over the phone or read from a notification preview.
Message Format
The message sent to the recipient follows this template:
{Your Account Name}: {CODE}. Valid for {TTL} minutes.For example, if your account name is Acme and the code is A3K9PZ:
Acme: A3K9PZ. Valid for 5 minutes.The account name is taken from your registered profile in the Console.
Expiry
OTP codes expire after 5 minutes by default. The exact expiry timestamp is returned in every send response:
{
"message": "OTP sent successfully",
"expiresAt": "2026-06-09T10:05:00.000Z"
}Use expiresAt to show a countdown timer or display a "resend" button in your UI.
Auto-Invalidation
When a new OTP is sent to a phone number on the same channel, any previous unused, unexpired codes for that number are automatically invalidated. This prevents confusion where a user tries an old code after requesting a new one.
Verification
Verification requires two fields — the phone number and the code submitted by the user:
{
"phone": "+628123456789",
"code": "A3K9PZ"
}The API checks that:
- A record exists for that phone + code + channel combination
- The code has not been used before
- The code has not expired
If all three conditions pass, the code is marked as used and verification succeeds. A used or expired code always returns a failure — codes cannot be verified more than once.
Error Responses
| Status | Body | Meaning | | --- | --- | --- | | 400 | Phone number is required | phone field missing from send request | | 400 | Phone and code are required | phone or code missing from verify request | | 400 | Invalid or expired OTP | Code not found, already used, or past expiresAt | | 402 | Insufficient balance | Account balance is below the cost of the send | | 503 | No default WhatsApp account is configured | No WhatsApp account has been set as default by an admin |
Choosing a Channel
Both channels produce the same OTP experience for the end user. The main differences:
| | SMS | WhatsApp | | --- | --- | --- | | Cost | 499 credits | 299 credits | | Requires device | SIM card | WhatsApp installed | | Delivery endpoint | /api/v1/otp/sms/send | /api/v1/otp/whatsapp/send | | Verify endpoint | /api/v1/otp/sms/verify | /api/v1/otp/whatsapp/verify |
Use the channel that best matches your user base. OTPs sent via SMS are verified only against SMS records, and WhatsApp OTPs only against WhatsApp records.