واجهة برمجة واتساب

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.