واجهة برمجة واتساب
Errors & Limits
Complete reference of API error codes, HTTP status codes, rate limits, and troubleshooting guide for the WhatsApp Business API.
HTTP Status Codes
| Status | Meaning |
|--------|---------|
| 200 OK | Request succeeded |
| 201 Created | Resource created (templates, broadcasts) |
| 400 Bad Request | Invalid request body or parameters |
| 401 Unauthorized | Missing or invalid API key |
| 403 Forbidden | Insufficient permissions |
| 404 Not Found | Resource doesn’t exist |
| 409 Conflict | Duplicate resource (e.g., template name) |
| 429 Too Many Requests | Rate limit exceeded |
| 500 Internal Server Error | Server error — retry with backoff |
Error Response Format
All errors return a consistent JSON structure:
{
"error": {
"code": "INVALID_RECIPIENT",
"message": "The recipient phone number is not registered on WhatsApp.",
"details": {
"field": "to",
"value": "1234567890"
},
"request_id": "req_abc123"
}
}
Error Codes Reference
Message Errors
| Code | HTTP | Description | Solution |
|------|------|-------------|----------|
| INVALID_RECIPIENT | 400 | Number not on WhatsApp | Verify the number is registered |
| INVALID_MESSAGE_TYPE | 400 | Unsupported message type | Check supported types in docs |
| MESSAGE_TOO_LONG | 400 | Text exceeds 4,096 chars | Shorten the message |
| OUTSIDE_WINDOW | 400 | 24h session expired | Use a template message |
| TEMPLATE_NOT_FOUND | 404 | Template doesn’t exist | Check name and language code |
| TEMPLATE_PAUSED | 400 | Template is paused by Meta | Fix quality issues, resubmit |
| MEDIA_TOO_LARGE | 400 | File exceeds size limit | Compress or resize the file |
| MEDIA_FORMAT_UNSUPPORTED | 400 | Unsupported file format | Convert to a supported format |
| RECIPIENT_BLOCKED | 400 | User blocked your number | Remove from contact list |
Authentication Errors
| Code | HTTP | Description | Solution |
|------|------|-------------|----------|
| INVALID_API_KEY | 401 | API key is invalid or revoked | Check/regenerate your API key |
| EXPIRED_API_KEY | 401 | API key has expired | Generate a new key |
| INSUFFICIENT_PERMISSIONS | 403 | Key lacks required scope | Use a key with correct permissions |
| IP_NOT_ALLOWED | 403 | Request from blocked IP | Add IP to allowlist |
Rate Limit Errors
| Code | HTTP | Description | Solution |
|------|------|-------------|----------|
| RATE_LIMITED | 429 | Too many requests/second | Wait and retry with backoff |
| DAILY_LIMIT_REACHED | 429 | Daily message quota exceeded | Upgrade plan or wait until reset |
| BROADCAST_LIMIT | 429 | Max broadcasts/day reached | Wait or upgrade plan |
Account Errors
| Code | HTTP | Description | Solution |
|------|------|-------------|----------|
| ACCOUNT_SUSPENDED | 403 | Account is suspended | Contact support |
| WABA_DISCONNECTED | 403 | WhatsApp Business Account disconnected | Reconnect in dashboard |
| NUMBER_NOT_VERIFIED | 403 | Phone number not verified | Complete verification flow |
Rate Limits
API Rate Limits (per API key)
| Plan | Requests/sec | Daily Messages | |------|-------------|----------------| | Free | 10 | 1,000 | | Premium | 100 | 100,000 | | Enterprise | Up to 1,000 | Unlimited |
WhatsApp Throughput (set by Meta)
Message throughput is controlled by Meta based on your phone number’s quality rating:
| Tier | Unique Users/24h | How to Reach | |------|-------------------|--------------| | Tier 1 | 1,000 | New numbers start here | | Tier 2 | 10,000 | Maintain quality + volume | | Tier 3 | 100,000 | Consistent quality + higher volume | | Tier 4 | Unlimited | Highest quality + highest volume |
StartMessaging handles all Meta-level throttling automatically — you don’t need to manage it yourself.
Implementing Retry Logic
async function sendWithRetry(payload, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch('https://api.startmessaging.com/v1/messages', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(payload),
});
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
if (response.status >= 500) {
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
continue;
}
return await response.json();
} catch (error) {
if (attempt === maxRetries) throw error;
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
}
}
}
FAQ
What should I do if I keep getting OUTSIDE_WINDOW errors?
The 24-hour customer service window has expired. You must use an approved template message to re-initiate the conversation.
How do I check my current rate limit usage?
Check the X-RateLimit-Remaining and X-RateLimit-Reset response headers on any API call.
My quality rating dropped — what can I do? Reduce marketing messages, improve opt-in practices, and make it easy for users to opt out. Quality ratings recover automatically when complaint rates decrease.