Rate Limits
Rate limits protect both the platform and your WhatsApp number — sending too fast is the fastest way to get a number banned. Limits are enforced per Device Key.
Limits
| Scope | Limit | Applies to |
|---|---|---|
| Per device (global) | 120 requests / minute | Every authenticated API call for that Device Key |
| Send burst | 20 / minute | POST /api/send-message |
| Group-send burst | 20 / minute | POST /api/group/send-message |
| Verify burst | 20 / minute | POST /api/verify-whatsapp |
| Tenant API key | 120 / minute | GET /api/devices/by-api-key |
The single-send and verify paths have a tighter 20/min burst ceiling on top of the global 120/min. This stops a script from using single-send as an unpaced bulk channel — for real volume, use bulk send, which runs through a paced, anti-ban queue.
Handling 429
When you exceed a limit you get 429 RATE_LIMITED with a Retry-After header (seconds):
HTTP/1.1 429 Too Many Requests
Retry-After: 12
{ "success": false, "error": { "code": "RATE_LIMITED", "message": "Rate limit exceeded" } }
Back off for the number of seconds in Retry-After, then retry. A simple, robust client:
async function callRapiwa(url, body, key) {
for (let attempt = 0; attempt < 5; attempt++) {
const res = await fetch(url, {
method: 'POST',
headers: { Authorization: `Bearer ${key}`, 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
if (res.status !== 429) return res
const wait = Number(res.headers.get('Retry-After') || 5)
await new Promise((r) => setTimeout(r, wait * 1000))
}
throw new Error('Rate limited: gave up after retries')
}
Best practices
- Never hammer single-send in a tight loop. Use bulk send for broadcasts — it paces sends for you.
- Respect
Retry-Afterinstead of retrying immediately. - Warm up new devices gradually; the engine also enforces warm-up and daily caps behind the scenes.