Rate Limits and Quotas

The request, send and check quotas on each plan, the headers that report what is left, and how throttled requests and 429 responses behave.

Updated rate-limitsquotasplans

Two different things can slow a Wapito request down, and they answer differently. Plan limits are the quotas you bought: how many requests a minute and a month, how many messages a day, how many number checks. Anti-ban controls are the limits the linked number needs whatever you bought: a send queue that paces messages, a warm-up ladder for new numbers, a guard on messages to strangers, and WhatsApp's own reach-out timelock. Both answer 429, but with different codes, and the right reaction is different for each. This page lists them all.

Plan limits

LimitSandboxPremium
Channels1Unlimited, billed per channel
API requests per minute, per channel60300
API requests per month1,000Unlimited
Messages sent per day150Unlimited (the warm-up ladder still applies)
Number checks per day302,000
Webhook endpoints25
Maximum media size16 MB64 MB
Dedicated proxy—Optional

The prices and the rest of the plan are on the pricing page. Three counters do the counting:

  • Requests — every call to /v1/* counts once toward the month, whatever it does. The per-minute limit is a fixed one-minute window per channel, so two channels in one account have two windows.
  • Sent — one per message accepted by a send endpoint (/messages/*, /stories/*, a message to a Channel). A send that is rejected — a bad recipient, a quota refusal, a timelock — is not counted, and one the engine refuses after acceptance is refunded.
  • Checks — one per phone number looked up. A bulk POST /contacts/check of fifty numbers costs fifty, whether or not they exist on WhatsApp.

Days and months are UTC: the daily counters reset at 00:00 UTC and the monthly one on the first of the month. The dashboard's Usage tab draws the last thirty days of each.

Reading what is left

Every response carries the per-minute state of the window it was counted in:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 41
X-RateLimit-Reset: 1789459260

X-RateLimit-Reset is the epoch second at which the window rolls over. For everything else — the daily and monthly quotas, the warm-up rung, the cold-send budget and the timelock — ask GET /channel/limits before a bulk run, and size the batch to the answer instead of discovering the cap through refusals:

{
  "plan": "premium",
  "rate_limit_per_minute": 300,
  "api_requests": { "cap": null, "used": 19422, "resets_at": "2026-10-01T00:00:00.000Z" },
  "sent": { "cap": null, "used": 412, "resets_at": "2026-09-16T00:00:00.000Z" },
  "number_checks": { "cap": 2000, "used": 38, "resets_at": "2026-09-16T00:00:00.000Z" },
  "warmup": { "day": 11, "cap": null, "ladder_complete": true },
  "cold_send": { "window_cap": 60, "used": 4, "resets_at": "2026-09-15T09:00:00.000Z" },
  "timelock": { "active": false, "reason": null, "until": null },
  "media_max_bytes": 67108864,
  "webhooks_max": 5
}

cap: null means the plan does not cap that dimension.

The 429 responses

All of them use the standard error envelope. Branch on code; the message is for humans.

codeWhich limitWhat to do
rate_limitedRequests per minute.Wait for the Retry-After header (seconds), then retry the same request.
quota_exceededA daily or monthly quota; details.quota names it, with used and resets_at.Wait for resets_at, or upgrade. Nothing to retry sooner.
send_rate_limitedThe channel's send queue is saturated.You are pushing sends faster than the queue drains; back off for a few seconds and slow the producer.
warmup_limitToday's warm-up rung; details carries day, cap, used.Stop sending for the day. The rung rises tomorrow.
cold_send_limitThis hour's budget of first messages to strangers.Send only to people who have written to you until the hour resets; see below.

And one that is not a 429 but belongs in the same handler: 423 reachout_timelocked, with details.until, means WhatsApp itself has paused new reach-outs from this number. Replies still go through; cold sends do not until until.

{
  "error": {
    "code": "quota_exceeded",
    "message": "The plan quota for this resource is exhausted.",
    "details": { "quota": "sent", "used": 150, "resets_at": "2026-09-16T00:00:00.000Z" },
    "request_id": "req_01JRQ8F4X9N2K7YB3C5V6W8H0T"
  }
}

A client that treats every 429 as "retry with exponential back-off" will hammer a daily quota uselessly for hours. The retryable one is rate_limited, and it tells you exactly how long to wait:

# --fail-with-body keeps the JSON error; -D - prints the headers so Retry-After is visible.
curl --fail-with-body -D - https://api.wapito.com/v1/messages/text \
  -H "Authorization: Bearer $WAPITO_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"to": "+15551234567", "body": "Your table is ready."}'

The send queue

Every channel has one first-in, first-out send queue. Messages leave it one at a time, spaced by the channel's send_delay_ms — 1,500 ms by default, and no lower than 500 ms on Sandbox — plus a random jitter of up to 1,500 ms, so a burst of a hundred API calls becomes a hundred sends over a few minutes that look like a person typing. If a call would have to wait more than twenty seconds in the queue it is refused with send_rate_limited instead of being held open, which is the signal that your producer is running ahead of the number.

Typing simulation rides on the same queue: a typing_time of up to fifteen seconds on a text send, or typing_simulation: "auto" in the channel settings, shows the recipient "typing…" for a duration proportional to the message before it is sent. These are anti-ban controls, not plan features, and they are the same on every plan — see the anti-ban guide.

The warm-up ladder

A number that has just been linked is on day 0 of a ladder that caps how many messages it may send each day, before the plan cap is even considered:

Day since first connection01234567 +
Sends allowed that day501002003505007501,000plan cap

The clock starts the first time the phone number connects and is not reset by a disconnect, a reconnect or a change of engine. It is reset when a different phone number is linked to the same channel — the ladder belongs to the number, because it is the number WhatsApp is judging. A send past the rung answers 429 warmup_limit; on Sandbox the plan's 150 a day is the lower of the two from day 2 on, and that case answers quota_exceeded instead, so the code always names the limit that actually stopped you.

The cold-send guard

A recipient is cold when they have never messaged the number, or when your first message to them went out less than 24 hours ago and they have not replied since. Groups and Channels are never cold. Each hour the channel may start only so many conversations with cold recipients:

Warm-up dayCold reach-outs per hour
0 – 110
2 – 620
7 +60 on Premium, 20 on Sandbox

What is counted is the number of new cold recipients contacted in the last hour, not the number of messages: a follow-up to a stranger you wrote to twenty minutes ago spends no second slot. What is blocked once the budget is spent is every cold send, follow-ups included — replies to people who have written to you keep flowing. The refusal is 429 cold_send_limit, and a refused send is not counted anywhere.

This is the control most likely to surprise a team migrating from a library that had no such thing. It exists because messages to people who never asked for them are what gets a number reported, and reports are what get it banned. The honest guide to avoiding bans explains the numbers behind the numbers.

The timelock

WhatsApp sometimes puts a number into a state where it may reply but may not start new conversations for a while. Wapito detects that from the engine and reports it in GET /channel/limits under timelock; while it is active, a cold send answers 423 reachout_timelocked with details.until, and replies go through unchanged. Treat it as a warning shot: the number has been doing something WhatsApp did not like, and the right response is to lower the volume, not to route around the lock.

Try it on your own number

Create a channel, link a WhatsApp number by QR or pairing code, and call the API in a couple of minutes. The Sandbox plan is free and needs no card.