Resend OTP
Resend a new OTP for an existing session when the user didn't receive the original code or it expired.
Endpointโ
POST /api/v1/otp/resend
Headersโ
X-API-Key: sk_live_your_api_key
Content-Type: application/json
Why Use This Endpoint?โ
- ๐ User Convenience - Allow users to request a new OTP without restarting the flow
- โก Quick Recovery - Resend to all original channels with one request
- ๐ฏ Same Session - Maintains the same session token for seamless UX
- ๐งช Sandbox Support - Returns new OTP in sandbox mode for testing
- ๐ Attempt Reset - Resets verification attempts for the session
Core Conceptโ
If a user doesn't receive the OTP or it expires, they can request a resend. The API generates a new OTP for the same session and sends it to all original channels. The session token remains valid.
Request Structureโ
Required Fieldsโ
| Field | Type | Description |
|---|---|---|
session_token | string | Session token from the original send OTP request |
Use Case Examplesโ
Example 1: User Didn't Receive OTPโ
User didn't receive the original OTP and requests a resend.
curl -X POST https://api.sendmator.com/api/v1/otp/resend \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
Success Response:
{
"success": true,
"expires_at": "2024-01-15T11:00:00.000Z",
"message": "OTP resent successfully"
}
Example 2: Resend in Sandbox Modeโ
Testing resend functionality in sandbox mode.
curl -X POST https://api.sendmator.com/api/v1/otp/resend \
-H "X-API-Key: sk_test_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
Sandbox Response:
{
"success": true,
"expires_at": "2024-01-15T11:00:00.000Z",
"message": "OTP resent successfully",
"sandbox_otps": {
"email": "789012",
"sms": "789012"
}
}
Example 3: Session Already Verifiedโ
User tries to resend after already verifying.
curl -X POST https://api.sendmator.com/api/v1/otp/resend \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
Error Response:
{
"statusCode": 400,
"message": "Session already verified",
"error": "Bad Request"
}
Example 4: Session Locked (Too Many Attempts)โ
User exhausted verification attempts and session is locked.
curl -X POST https://api.sendmator.com/api/v1/otp/resend \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"session_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
Error Response:
{
"statusCode": 400,
"message": "Session is locked due to too many failed attempts",
"error": "Bad Request"
}
Response Fieldsโ
Success Responseโ
| Field | Type | Description |
|---|---|---|
success | boolean | Always true for successful resend |
expires_at | string | ISO 8601 timestamp when session expires |
message | string | Human-readable success message |
sandbox_otps | object | New OTP codes (only in sandbox mode) |
Error Responseโ
{
"statusCode": 400,
"message": "Error description",
"error": "Bad Request"
}
Common Error Responsesโ
| Status Code | Error Message | Cause | Solution |
|---|---|---|---|
| 400 | Session already verified | Session was successfully verified | No resend needed |
| 400 | Session is locked | Too many failed verification attempts | Start new session with send OTP |
| 400 | Session not found | Invalid or expired token | Start new session with send OTP |
| 401 | Invalid API key | API key missing or incorrect | Check API key |
| 402 | Insufficient balance | Not enough wallet credits | Add credits to wallet |
| 429 | Rate limit exceeded | Too many resend requests | Wait before retrying |
How Resend Worksโ
- Validates Session - Checks if session exists and is still active
- Generates New OTP - Creates a new OTP code for all channels
- Sends to All Channels - Resends to the same channels as original request
- Resets Attempts - Verification attempt counter is reset
- Keeps Same Token - Session token remains unchanged
- Updates Expiry - Session expiry time is extended
Best Practicesโ
1. User Experienceโ
- Show Resend Button - Display after initial OTP is sent
- Rate Limit UI - Disable button for 30-60 seconds after resend
- Clear Feedback - Show success message when OTP is resent
- Expiry Timer - Show countdown and auto-enable resend when expired
- Alternative Channels - Suggest trying different channel if available
2. Rate Limitingโ
Implement client-side rate limiting:
const [canResend, setCanResend] = useState(false);
const [countdown, setCountdown] = useState(60);
const handleResend = async () => {
try {
const response = await fetch('/api/v1/otp/resend', {
method: 'POST',
headers: {
'X-API-Key': 'sk_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({
session_token: sessionToken
})
});
const data = await response.json();
if (response.ok) {
showSuccess('OTP resent successfully');
// Disable resend button for 60 seconds
setCanResend(false);
setCountdown(60);
const timer = setInterval(() => {
setCountdown(prev => {
if (prev <= 1) {
setCanResend(true);
clearInterval(timer);
return 0;
}
return prev - 1;
});
}, 1000);
}
} catch (error) {
showError('Failed to resend OTP');
}
};
3. Error Handlingโ
Handle different error scenarios gracefully:
const handleResend = async () => {
try {
const response = await resendOtp(sessionToken);
if (response.success) {
showMessage('New OTP sent successfully');
}
} catch (error) {
if (error.message.includes('already verified')) {
// Redirect to success page
window.location.href = '/dashboard';
} else if (error.message.includes('locked')) {
// Session locked, need new OTP session
showError('Too many attempts. Please start over.');
redirectToResendFlow();
} else if (error.message.includes('not found')) {
// Session expired, restart flow
showError('Session expired. Starting new verification.');
restartOtpFlow();
} else {
showError('Failed to resend. Please try again.');
}
}
};
4. Integration Patternsโ
Pattern 1: Simple Resendโ
// Minimal resend implementation
const resendOtp = async (token) => {
const response = await fetch('/api/v1/otp/resend', {
method: 'POST',
headers: {
'X-API-Key': 'sk_live_your_api_key',
'Content-Type': 'application/json'
},
body: JSON.stringify({ session_token: token })
});
return response.json();
};
Pattern 2: Resend with Countdownโ
// Resend with countdown timer
const ResendButton = ({ sessionToken }) => {
const [countdown, setCountdown] = useState(60);
const [canResend, setCanResend] = useState(false);
useEffect(() => {
if (countdown > 0) {
const timer = setTimeout(() => setCountdown(countdown - 1), 1000);
return () => clearTimeout(timer);
} else {
setCanResend(true);
}
}, [countdown]);
const handleResend = async () => {
await resendOtp(sessionToken);
setCountdown(60);
setCanResend(false);
};
return (
<button onClick={handleResend} disabled={!canResend}>
{canResend ? 'Resend OTP' : `Resend in ${countdown}s`}
</button>
);
};
When to Use Resendโ
Good Use Casesโ
- User didn't receive the OTP
- OTP was delayed or lost in delivery
- User accidentally deleted the message
- User wants to try a different device
- Session is about to expire
When NOT to Useโ
- Session already verified (redirect to success page)
- Session is locked (start new session with send OTP)
- User wants to change phone/email (start new session with send OTP)
Rate Limitsโ
Resend endpoint limits:
- 3 resends per session - Prevents abuse
- 5 resends per 10 minutes per user
- 20 resends per hour per IP address
Next Stepsโ
- Send OTP - Learn how to send OTPs
- Verify OTP - Learn how to verify OTPs
- OTP Overview - Understand OTP concepts