01What is the token bucket algorithm?
The token bucket algorithm limits the rate of events while still allowing short bursts. Picture a bucket that holds at most C tokens and is topped up at a steady r tokens per second. Every request must take a token before it goes ahead: if one is available it proceeds at once; if the bucket is empty it waits for the next token or is refused. Over the long run requests can never exceed r per second, yet after a quiet spell up to C can go out back to back.
Two numbers fully describe a bucket, and they do different jobs. The capacity C is the burst allowance — how many requests can leave together when the bucket is full. The refill rate r is the sustained throughput. An implementation needs no timer: it stores the token count and the time of the last update, and on each request adds elapsed × r tokens (capped at C) before checking whether one can be spent.
WhatsApp senders usually run the algorithm on their own side, to pace outbound sends below what the platform allows. A Cloud API phone number has a default throughput of up to 80 messages per second, exceeding it returns error 130429, and sending too fast to a single recipient trips a separate pair rate limit (error 131056). That is the difference from rate limiting, which describes the limits Meta enforces, and from backpressure, the signal that tells producers upstream to slow down when your bucket and queue fill up.
Key takeaways
- The token bucket algorithm refills tokens at a fixed rate up to a capacity; each request spends one and waits, or is refused, when none are left.
- Capacity sets the largest burst; the refill rate sets the long-run average throughput.
- Run one client-side to pace sends under a WhatsApp number's throughput, which is up to 80 messages per second by default.
- In any one-second window a bucket can release its capacity plus one second of refill, so keep the two together under the limit.
- The token bucket is what you run yourself; rate limiting is what Meta enforces when you do not, answering with error 130429.
02 · How it works, step by step
How does the token bucket algorithm work?
- Step 1
Choose the rate
Set the refill rate a little under the limit you must respect — for a number on the default 80 messages per second, perhaps 60 to 70 — leaving headroom for retries and other senders on the same number.
- Step 2
Choose the capacity
Pick the burst you are willing to release at once. If no one-second window may exceed 80 sends, keep capacity plus refill rate at or below 80 — for example 20 tokens refilling at 60 per second.
- Step 3
Spend a token per send
Before each Cloud API call, take a token. If none is left, wait until the next one is due instead of sending anyway and collecting a 130429.
- Step 4
Share one bucket per number
Workers sending from the same number need one bucket, held by a single dispatcher or in a shared store updated atomically (for example a Redis script). A bucket per worker multiplies the rate.
- Step 5
Add small buckets per recipient
Keep a small bucket per recipient as well, so a flurry of messages to one customer cannot trip the pair rate limit while the number-level bucket still has tokens.
- Step 6
Adapt when the platform pushes back
If 130429 or 131056 still appears, lower the refill rate for a while and raise it slowly. Those errors are the signal that your settings are too optimistic.
03The token bucket algorithm in code
export class TokenBucket {constructor({ capacity, refillPerSecond }) {this.capacity = capacity;this.rate = refillPerSecond;this.tokens = capacity;this.updated = performance.now();}#refill() {const now = performance.now();const elapsed = (now - this.updated) / 1000;this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.rate);this.updated = now;}/** Resolves once a token has been taken. */async take() {for (;;) {this.#refill();if (this.tokens >= 1) {this.tokens -= 1;return;}const waitMs = ((1 - this.tokens) / this.rate) * 1000;await new Promise((resolve) => setTimeout(resolve, waitMs));}}}// 20 + 60 <= 80: never more than 80 sends in any one-second window.const bucket = new TokenBucket({ capacity: 20, refillPerSecond: 60 });for (const job of jobs) {await bucket.take();sendTemplate(job); // POST https://graph.facebook.com/v26.0/{PHONE_NUMBER_ID}/messages}
A pacer waits for the next token instead of refusing the send. The send itself is not awaited, so slow responses do not reduce the rate.
04The token bucket algorithm: key facts and limits
- Parameters
- Capacity C (burst) and refill rate r (tokens per second)
- Most released in any 1-second window
- C + r
- Long-run maximum rate
- r per second
- Default Cloud API throughput
- Up to 80 messages per second per number
- Upgraded throughput
- 1,000 messages per second, automatic when eligible
- Errors when you exceed limits
- 130429 (throughput), 131056 (pair rate limit)
05Why does the token bucket algorithm matter?
Without pacing, a broadcast or a post-outage recovery fires as fast as the workers allow, hits the throughput ceiling within a second and spends the rest of the run retrying 130429 errors — slower overall than sending at the right rate from the start. A token bucket turns 'as fast as possible' into 'as fast as allowed', keeps bursts within limits you choose, and gives every worker one shared rule, so throughput is predictable and OTPs are not starved by marketing traffic.
06Example: Pacing a Thrissur jeweller's festive broadcast
A Thrissur jeweller sends a Dhanteras offer to 60,000 opted-in customers from a number on the default throughput of up to 80 messages per second. The first attempt, with no pacing, ran 20 workers flat out: within a second 130429 errors appeared and retries dragged the run out. With one shared bucket of 20 tokens refilling at 60 per second, the send settles at a steady 60 messages per second and finishes in under 17 minutes without throughput errors, while the remaining headroom on the number keeps login OTPs flowing.
07 · Common mistakes, and the fix
Common mistakes with the token bucket algorithm
One bucket per worker
Ten workers each pacing at 60 per second send 600 per second from the same number. The bucket must be shared, in one dispatcher or an atomic shared store.
Forgetting the burst
A full bucket of 80 tokens refilling at 80 per second can release 160 sends in one second. Size capacity and rate together against the window the limit is measured over.
Refusing instead of waiting
A server-side limiter answers 429; a client-side pacer should hold the send until a token is due. Dropping sends to stay under a limit loses messages.
Ignoring per-recipient limits
A number-level bucket does not stop five order updates to one customer in the same second. Add a per-recipient bucket or combine messages to the same person.
Settings that never change
When a number is upgraded to 1,000 messages per second, a bucket still tuned for 80 wastes most of the capacity. Read the number's current throughput and adjust.
08 · Tips from the bench
Best practices for the token bucket algorithm
- Give OTPs and other critical traffic their own bucket or priority on the same number.
- Log how long each send waited for a token; rising waits mean you need more throughput, not more workers.
- Use a monotonic clock (
performance.now(), RedisTIME) so a clock change can never mint tokens. - Cut the refill rate automatically when 130429 appears, then restore it gradually.