Blue Reacher
Rate limits12 / 46

Rate limits

The request budget per app and installation, the stricter per-workspace send limit, the X-RateLimit headers, and how to back off from a 429.

Two budgets apply. A general limit covers every route. A stricter limit covers outbound sends, per workspace. Going over either one returns 429.

Your limits depend on your app

Rate limits are set per app when the app is registered. The numbers on this page are the defaults a new app starts with. Yours may be higher or lower, so read the X-RateLimit-* headers instead of hard-coding these values. Contact support if your integration needs a larger budget.

Standard limits

Applied per app, per installation. Each user who installs your app gets their own budget, and one installation using it up does not affect the others. Every route counts, sends included.

DefaultWindowScope
100 requests10 seconds, burstPer app, per installation
200,000 requestsOne UTC day, resets at 00:00 UTCPer app, per installation

Once the daily budget is used, every request answers 429 until the reset.

The token endpoints are outside these limits and never answer 429.

Usage headers

Every response that passes authentication carries your current budget. A 401 or 402 is refused before the budget is checked, so it carries none.

HeaderMeaning
X-RateLimit-Limit-DailyYour daily allowance.
X-RateLimit-Daily-RemainingRequests left today.
X-RateLimit-Interval-MillisecondsThe burst window length.
X-RateLimit-MaxRequests allowed per burst window.
X-RateLimit-RemainingRequests left in the current burst window.

A 429 also carries Retry-After with the number of seconds to wait.

Message send limit

POST /v1/messages and POST /v1/messages/scheduled have their own budget on top of the standard limits, on a sliding window per workspace.

LimitWindowScope
30 messages15 minutes, slidingPer workspace

The 31st send inside any 15-minute window is refused with 429. Wait for older sends to leave the window. Attachments are limited to one per message, up to 5 MB.

Check iMessage limit

Apple limits lookups. Each line takes 10 Check iMessage calls a minute. Beyond that the route answers 429 with RATE_LIMITED in the message.

The 429 body

The standard limits, burst or daily:

{
  "success": false,
  "message": "Daily rate limit exceeded: 200,000 requests per day (resets 00:00 UTC).",
  "error": "RateLimitExceeded"
}

The send limit:

{
  "message": "Too many queued messages for this workspace",
  "error": "RateLimitExceeded"
}

Both carry "error": "RateLimitExceeded". Check that field, not the message text.

Handling a 429

A 429 means the request was refused, not that it failed. Wait, then retry with exponential backoff and jitter.

async function withBackoff(fn, maxRetries = 5) {
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const res = await fn();
    if (res.status !== 429) return res;
    const retryAfter = Number(res.headers.get("retry-after")) * 1000;
    const delay = retryAfter || Math.min(2 ** attempt * 1000, 60_000) + Math.random() * 1000;
    await new Promise((r) => setTimeout(r, delay));
  }
  throw new Error("Rate limited after retries. Slow the request rate.");
}

Bulk sending

Spread sends evenly instead of bursting. A queue that releases one message every 30 seconds per workspace, which is 2 messages a minute, never hits the send limit. See Deliverability for why slow and steady also keeps lines healthy.

On this page