Sendexa LogoDocs
OTP API
Stable

OTP API

Deliver secure one-time passwords to any mobile number. Configurable length, expiry, and type — with automatic rate limiting and brute-force protection built in so you can focus on your product.

Multiple PIN Types

Choose NUMERIC (4–8 digits), ALPHANUMERIC (6–12 chars), or ALPHABETIC codes to match your security requirements.

Configurable Expiry

Set expiry from 1 minute to 24 hours with automatic invalidation — no manual cleanup needed.

Built-in Rate Limiting

Automatic cooldown periods and max-attempt enforcement prevent brute force and OTP spam.

Metadata Support

Attach custom context (userId, sessionId, IP) to each OTP request for audit trails.

Resend & Cooldown

Resend OTPs after a configurable cooldown without creating duplicate active codes.

PCI-DSS Compliant

Codes are encrypted at rest with automatic expiration and brute-force protection built in.

Default Expiry

5 min

Configurable 1–1440 min

Max Attempts

3

Default (max 10)

Cooldown

60 s

Between resends

Code Length

4–12

Chars (type-dependent)

Quick Start — 3-Step OTP Flow
1

Request OTP

Call /v1/otp/request — Sendexa generates a secure code and sends it by SMS.

Bash
curl -X POST 'https://api.sendexa.co/v1/otp/request' \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \
-d '{
"phone": "0244123456",
"from": "MyBrand",
"message": "Your code is {code}. Valid for {amount} {duration}.",
"pinLength": 6,
"pinType": "NUMERIC",
"expiry": { "amount": 5, "duration": "minutes" }
}'
JSON
{
"success": true,
"data": {
"id": "otp_abc123xyz",
"expiresAt": "2024-01-15T10:35:00.000Z"
}
}
2

User enters the code

Display an input in your UI. Store the id from step 1 — you'll need it for verification.

3

Verify the code

Call /v1/otp/verify with the OTP ID and the code the user entered.

Bash
curl -X POST 'https://api.sendexa.co/v1/otp/verify' \
-H 'Content-Type: application/json' \
-H 'Authorization: Basic YOUR_DASHBOARD_BASE64_TOKEN' \
-d '{
"id": "otp_abc123xyz",
"pin": "482910"
}'
JSON
{
"success": true,
"message": "OTP verified successfully",
"data": { "verified": true }
}
PIN Types
TypeLengthExampleBest For
NUMERIC4–8 digits482910Login, general verification (easiest to type)
ALPHANUMERIC6–12 charsA7B9X2K4Financial transactions, high-security flows
ALPHABETIC5–10 lettersKPTMRBVoice-read verification codes
Common Errors
400ACTIVE_OTP_EXISTS

An unexpired OTP is already active for this phone. Show the remaining countdown to the user.

429RATE_LIMIT_EXCEEDED

Max 3 OTP requests per phone per hour. Use retryAfter from the response for the countdown.

400OTP_EXPIRED

The OTP has passed its expiry time. Prompt the user to request a new code.

400INVALID_PIN

Wrong code entered. Check attemptsRemaining — lock the flow at 0 to prevent brute force.

404OTP_NOT_FOUND

The OTP ID does not exist or was already verified. Redirect to request a new OTP.

Message Template Variables

Use these placeholders in the message field — they are replaced at send time:

{code}

The generated OTP code (required)

{amount}

The expiry amount (e.g. 5)

{duration}

The expiry unit (minutes / hours)

Example: "Your code is {code}. Valid for {amount} {duration}." "Your code is 482910. Valid for 5 minutes."

USSD Fallback — *889*142#

When SMS is delayed or unavailable, users can dial *889*142# from any mobile phone to retrieve a pending OTP via USSD — no internet or SMS delivery required.

1User dials*889*142# on any mobile network
2Enter phone numberThe number the OTP was sent to
3Retrieve codeThe active OTP is displayed on screen
4Enter in your appUser types the code — verification works identically

SMS delayed

Carrier congestion or network issues holding up delivery.

No data needed

Works on feature phones and areas with no internet access.

Same session

The OTP ID and expiry are unchanged — verify as normal.

The USSD fallback is active automatically for all OTP requests — no extra configuration required. The code is available until the session expires or the OTP is verified.