OTP API Rate Limits
The OTP API implements intelligent rate limiting to balance security, user experience, and abuse prevention.
Rate Limit Overview
| Endpoint | Rate Limit | Window | Purpose |
|---|---|---|---|
POST /api/v1/otp/send | 100 requests | 1 minute | Allow high-concurrency legitimate use |
POST /api/v1/otp/verify | 300 requests | 1 minute | Support multiple concurrent verification attempts |
POST /api/v1/otp/resend | 20 requests | 1 minute | Allow reasonable resend attempts |
Detailed Breakdown
Send OTP - 100 requests/minute
Rationale:
- Supports high-traffic applications with concurrent users
- Allows bulk OTP sending for batch operations
- Prevents spam and abuse while maintaining usability
Use Cases:
- User onboarding flows with multiple steps
- E-commerce checkout with phone/email verification
- Banking apps with transaction confirmations
- Bulk user verification campaigns
Example Calculation:
100 requests/minute = 1.67 requests/second
- Small app: ~100 users verifying per minute → ✅ Supported
- Medium app: ~5,000 users/hour → ✅ Supported
- Large app: ~100,000 users/hour → ✅ Supported (distributed over time)
Abuse Prevention:
- Individual OTP sessions still have attempt limits (default: 3-5)
- Expired OTPs automatically invalidate
- Wallet balance prevents unlimited sending
Verify OTP - 300 requests/minute
Rationale:
- Verification attempts are more frequent than sends
- Users may mistype OTPs multiple times
- Progressive verification allows multiple channels
Use Cases:
- Users entering OTP codes from email/SMS
- Progressive verification (email first, then SMS)
- Retry after incorrect OTP entry
- Multiple devices verifying simultaneously
Example Scenario:
User Journey:
1. Receives OTP via email + SMS
2. Attempts email OTP → Wrong code (1st attempt)
3. Attempts email OTP → Wrong code (2nd attempt)
4. Checks SMS, enters correct code → ✅ Success
5. Later verifies SMS channel → ✅ Success
Total API calls: 4 verify requests in ~2 minutes → ✅ Well within limits
Security Layers:
- Per-session attempt limits (3-5 attempts per session)
- OTP expiry (default: 10 minutes)
- Account lockout after repeated failures
- Rate limit still prevents brute-force at API level
Resend OTP - 20 requests/minute
Rationale:
- Users occasionally need to resend OTPs
- Delivery failures require resends
- Progressive escalation (email → SMS → WhatsApp)
Use Cases:
- Email delivery delayed
- User didn't receive first OTP
- OTP expired before user entered it
- Channel switching (email → SMS)
Example Scenario:
Legitimate User:
1. Request OTP via email → Not received (1 minute wait)
2. Resend OTP → Still not received
3. Try SMS instead → Resend to SMS channel
4. Success! → Verify
Total resends: 3 in ~5 minutes → ✅ Within limits
Abusive Pattern (Blocked):
- 25 resends in 1 minute → ❌ Rate limited after 20
Rate Limit Headers
All OTP endpoints return rate limit information in response headers:
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1679520000
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when window resets |
Rate Limit Exceeded Response
When rate limit is exceeded:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"statusCode": 429,
"message": "ThrottlerException: Too Many Requests",
"error": "Too Many Requests"
}
Recommended Client Behavior:
- Check
X-RateLimit-Resetheader - Calculate wait time:
resetTime - currentTime - Display user-friendly message
- Implement exponential backoff
- Retry after wait period
Multi-Layer Protection
Rate limits work alongside other security measures:
1. Per-Session Limits
// OTP session configuration
{
max_attempts: 3, // Max verification attempts per session
expiry_minutes: 10, // Session expires after 10 minutes
lockout_on_failure: true // Lock after max attempts
}
2. Per-Recipient Throttling
- Same email/phone number: 5 OTPs per 5 minutes
- Prevents harassment and spam
- Independent of team rate limits
3. Wallet Balance
- Each OTP costs credits
- Prevents unlimited spam
- Natural abuse prevention
4. IP-Based Tracking
- Suspicious patterns flagged
- Multiple failed attempts logged
- Can trigger additional verification
Best Practices
For Developers
1. Implement Retry Logic
async function sendOTPWithRetry(payload, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await api.post('/v1/otp/send', payload);
} catch (error) {
if (error.response?.status === 429) {
const resetTime = error.response.headers['x-ratelimit-reset'];
const waitTime = (resetTime * 1000) - Date.now();
if (i < maxRetries - 1 && waitTime > 0) {
await sleep(waitTime);
continue;
}
}
throw error;
}
}
}
2. Display Remaining Limits
const response = await api.post('/v1/otp/send', payload);
const remaining = response.headers['x-ratelimit-remaining'];
if (remaining < 10) {
console.warn(`Low rate limit: ${remaining} requests remaining`);
}
3. Handle Rate Limit Errors Gracefully
try {
await api.post('/v1/otp/send', payload);
} catch (error) {
if (error.response?.status === 429) {
showUserMessage('Too many requests. Please try again in a moment.');
// Exponential backoff
}
}
For End Users
Clear Communication:
- "We've sent a verification code to your email"
- "Didn't receive it? Check spam folder first"
- "Click 'Resend' to get a new code"
- "You can resend up to 20 times per minute"
Progressive Disclosure:
Attempt 1: "Resend code"
Attempt 3: "Resend code (check spam folder)"
Attempt 5: "Resend code (try SMS instead)"
Monitoring and Alerts
Track Rate Limit Usage
Key Metrics:
- Rate limit hit rate (% of requests throttled)
- Average remaining quota per team
- Peak usage times
- Abusive patterns
Alert Thresholds:
alerts:
rate_limit_hit_rate_high:
condition: hit_rate > 5%
action: Review rate limits, may be too restrictive
rate_limit_hit_rate_low:
condition: hit_rate < 0.1%
action: Limits may be too permissive
suspicious_pattern:
condition: same_ip_multiple_teams > 10
action: Flag for abuse investigation
Comparison with Industry Standards
| Service | Send Limit | Verify Limit | Notes |
|---|---|---|---|
| Sendmator | 100/min | 300/min | Balanced for high concurrency |
| Twilio Verify | 10/sec (600/min) | No public limit | Enterprise-focused |
| Firebase Auth | 100/min (default) | Varies by plan | Similar to Sendmator |
| Auth0 | 50/sec (3000/min) | No public limit | Very permissive |
| AWS SNS | 20/sec (1200/min) | N/A | SMS-only service |
Sendmator's Position:
- ✅ More generous than Firebase (same send limit, higher verify)
- ✅ Suitable for small-to-medium applications
- ✅ Can scale to large applications with proper distribution
- ✅ Better than most competitors for verification attempts
Upgrading Limits
Need higher limits? Contact support with:
- Current usage patterns
- Expected growth
- Use case description
- Peak traffic times
Enterprise customers can get:
- Custom rate limits per team
- Dedicated infrastructure
- Priority support
- SLA guarantees
Testing Rate Limits
Use our load testing scripts:
# Test with 100 concurrent requests
npx ts-node scripts/test-otp-load.ts \
--total-requests 1000 \
--concurrency 100
# Should complete without rate limit errors
See Load Testing Documentation for details.
Frequently Asked Questions
Q: Why are limits per team, not per API key? A: Teams represent billing units. This prevents one API key from consuming all resources.
Q: Can I batch OTP sends? A: Yes! 100 requests/minute allows batching. Consider queuing large batches to stay within limits.
Q: What happens if I hit the limit?
A: You'll receive a 429 response. Wait for the window to reset (check X-RateLimit-Reset header).
Q: Are sandbox requests rate limited? A: Yes, same limits apply to prevent abuse of sandbox mode.
Q: Can I request a temporary limit increase? A: Contact support for special events (product launches, marketing campaigns).
Changelog
2026-03-18
- Increased send limit: 5/5min → 100/min (20x improvement)
- Increased verify limit: 10/min → 300/min (30x improvement)
- Increased resend limit: 3/5min → 20/min (33x improvement)
- Rationale: Support high-concurrency use cases and improve UX
Previous (Before 2026-03-18)
- Send: 5 requests per 5 minutes
- Verify: 10 requests per minute
- Resend: 3 requests per 5 minutes
- Issue: Too restrictive for legitimate high-traffic use