Errors & Limits
Common errors and how to handle them. All APIs return structured error responses.
HTTP Status Codes
| Status | Meaning | Typical Cause | Retry? |
|---|---|---|---|
200 |
OK | Request succeeded | No |
201 |
Created | Resource created | No |
400 |
Bad Request | Invalid field/format | No — fix and retry |
401 |
Unauthorized | Missing/invalid auth token | Maybe — check token expiry |
403 |
Forbidden | Permission denied | No — check organization/role |
404 |
Not Found | Resource doesn't exist | No |
429 |
Too Many Requests | Rate limit exceeded | Yes — wait Retry-After seconds |
500 |
Server Error | Server error | Yes — after 5+ seconds |
502 |
Bad Gateway | Temporarily unavailable | Yes — after 5+ seconds |
503 |
Service Unavailable | Server maintenance | Yes — check status page |
Error Response Format
Most errors return a JSON body with details:
{
"message": "Human-readable error message",
"error": "machine_error_code"
}
Example:
{
"message": "The email field is required.",
"errors": {
"email": ["The email field is required."]
}
}
Common Errors
401 Unauthorized
Cause: Missing, invalid, or expired authentication token.
Fix:
- Ensure
Authorization: Bearer <token>header is present - Re-login if the token expired:
POST /api/agent/login - For OTP API, check
X-Wallin-OTP-Key: <key>header
403 Forbidden
Cause: You don't have permission to access this resource (wrong organization, role, etc.).
Fix:
- Verify you belong to the organization (check
X-Organization-Idheader) - Ensure your role allows the action (e.g., agents can't create campaigns)
- Ask an admin to grant permission if needed
429 Too Many Requests
Cause: You exceeded the rate limit.
Response includes Retry-After header:
Retry-After: 60
Fix:
- Wait the specified seconds before retrying
- Implement exponential backoff: 1s, 2s, 4s, 8s, etc.
- For OTP API, check daily/monthly quota at
/otp-applications
Rate Limits:
| Endpoint | Limit | Reset |
|---|---|---|
| Agent API (all) | 100 requests/minute | Per minute |
| OTP Send | 5 per phone/hour, 20 per IP/hour | Hourly |
| OTP Verify | 3 attempts per code | Per code |
| WhatsApp Send | Varies by Meta WABA quality | Varies |
500 Internal Server Error
Cause: Server error (rare).
Fix:
- Retry after 5–10 seconds
- If it persists, contact support
- Check https://status.wallin.example for status updates
Validation Errors
When a request has invalid fields, you get a 400 Bad Request with details:
{
"message": "The given data was invalid.",
"errors": {
"phone_number": ["Phone number must be in E.164 format (e.g. +201001234567)."],
"code": ["The code field is required."]
}
}
Fix:
- Correct the field values and resubmit
- Check the error message for the exact requirement
OTP-Specific Errors
Send Error: rate_limit_exceeded
Max 5 OTPs per phone number per hour.
{
"message": "Maximum 5 OTPs per hour per phone number",
"error": "rate_limit_exceeded",
"retry_after": 3600
}
Fix: Wait 1 hour or use a different phone number.
Send Error: quota_exceeded
Your organization hit its monthly OTP limit.
{
"error": "quota_exceeded"
}
Fix: Upgrade your plan at /organizations/settings → Billing.
Verify Error: expired
The OTP code expired (default 5 minutes).
{
"data": {
"verified": false,
"error": "expired"
}
}
Fix: Call /resend to issue a new code.
Verify Error: max_attempts_exceeded
User exceeded the max wrong guesses (default 3).
{
"data": {
"verified": false,
"error": "max_attempts_exceeded",
"attempts_remaining": 0
}
}
Fix: Call /resend to issue a new code (resets attempts).
Verify Error: already_verified
The code was already used.
{
"data": {
"verified": false,
"error": "already_verified"
}
}
Fix: The code is no longer valid; a new OTP must be sent.
WhatsApp-Specific Errors
Send Error: Template Rejected
Template is not approved by Meta.
{
"error": "Failed to send message"
}
Fix:
- Check template status at
/templates - If rejected, review Meta's rejection reason
- Resubmit with corrections or use a different template
Send Error: Window Closed (WhatsApp)
Customer hasn't messaged in 24 hours; free-form sends are blocked.
{
"error": "Failed to send message"
}
Fix:
- Wait for the customer to message you
- Use a template with MARKETING or OTP category (if your WABA supports it)
- Check
window_statein conversation details
Send Error: Contact Not Found
Phone number is not connected to the channel.
{
"error": "Failed to send message"
}
Fix:
- Verify the phone number format (E.164, e.g.,
+201001234567) - Ensure the contact has WhatsApp/Instagram/Messenger connected
- Check the business account is correct
Rate Limiting Strategy
Best practices for handling rate limits:
-
Use exponential backoff:
retry_after = min(retry_after * 2, 300) // Cap at 5 minutes -
Read
Retry-Afterheader:const retryAfter = response.headers['retry-after']; setTimeout(() => retry(request), retryAfter * 1000); -
Batch requests:
- Group API calls and make them in parallel (up to rate limit)
- Avoid rapid sequential requests
-
Monitor quota:
- Check OTP monthly usage at
/otp-applications - Check message usage at
/organizations/settings→ Billing - Upgrade proactively before hitting limits
- Check OTP monthly usage at
Plan Message Limits
| Plan | Messages/Month | OTP Requests/Month |
|---|---|---|
| Free | 1,000 | 100 |
| Starter | 10,000 | 5,000 |
| Professional | 100,000 | 50,000 |
| Enterprise | Unlimited | Unlimited |
Message count includes:
- Broadcast messages sent
- Agent messages sent
- OTP messages sent
Hitting the limit blocks further sends until next month or plan upgrade.
Debugging Tips
- Log all responses: Keep full request/response logs for troubleshooting
- Check organization context: Ensure
X-Organization-Idis correct - Verify token freshness: Re-login if requests start failing with 401
- Test in sandbox: Use
WHATSAPP_SIMULATE_API=truelocally before production - Monitor Meta status: WhatsApp outages affect sends; check https://status.meta.com
Support
For persistent errors:
- Collect the full request and response (including headers)
- Note the timestamp and endpoint
- Contact support@wallin.example with details