Skip to main content

Rate limiting

BlueSender enforces several rate limits that an integration may observe. The two below are the ones a typical CRM message-routing flow will hit; additional limiters apply to provisioning and OAuth endpoints (see Other rate limits below).

1. HTTP webhook rate limit (per locationId)​

The BlueSender backend caps the rate of inbound HTTP webhook calls per locationId. This protects the backend from a misbehaving CRM flooding a single tenant.

Keying. The limiter keys on the request body's top-level locationId only when it is a valid 3–200 character alphanumeric string. Requests with a missing, malformed, or out-of-range value fall back to IP-based keying instead — meaning multiple unrelated tenants behind the same source IP can share the same limiter bucket. Send a valid locationId on every request to avoid this collision. The format check is on by default and can be disabled by an operator with RATE_LIMIT_VALIDATE_LOCATION_ID=false (any other value, including unset, leaves the check enabled).

Trigger and response​

ParameterDefault
Window1 minute (fixed)
Max requests per window60 / locationId / minute (tunable per deployment via RATE_LIMIT_CRM_WEBHOOK)
Action on exceededReject with HTTP 429

When the limit is exceeded, the webhook handler does not run — the request is rejected at the rate-limiter layer with:

{
"error": "TOO_MANY_REQUESTS",
"message": "Too many webhook requests for this location, please try again later."
}

The RateLimit-* standard headers are also returned, so clients that read them can pace themselves automatically.

  1. On HTTP 429, back off and retry. Honor the Retry-After / RateLimit-Reset headers if your HTTP client surfaces them.
  2. For burst-prone workloads, apply your own client-side rate limit below the configured cap.
  3. Coordinate with the BlueSender operator if your integration's sustained rate exceeds the default — the cap is tunable and raising it for a known integration is preferable to a tight retry loop.

2. Mac automation-queue limit​

Once a webhook is forwarded to the Mac, every outbound send goes through a single FIFO automation queue with a fixed depth (500 pending jobs across all message types). When the queue is full, the message is rejected and the failure is reported back to the CRM through the standard status-update channel (PUT /conversations/messages/{messageId}/status):

{
"status": "failed",
"error": {
"code": "RATE_LIMITED",
"type": "error",
"message": "Automation queue full; dropped to prevent unbounded backlog"
}
}

The queue covers all outbound work:

  • Plain text messages.
  • Messages with attachments or animation effects.
  • Outbound reactions (Tapbacks) — see Reactions: Outbound.
  • Outbound standalone stickers — see Stickers: Outbound.

In practice, plain text sends drain quickly enough that you'll rarely see RATE_LIMITED on a text-only workload — but the path exists, so any sustained burst at high enough volume can trip the 500-job cap.

  • Treat RATE_LIMITED as a transient, retryable failure.
  • Back off briefly (~30 seconds is reasonable — the queue drains as the Mac completes work) before re-sending.
  • For burst-prone workloads, apply your own client-side rate limit at ~50 ops/minute on the affected message types.
  • Don't retry indefinitely on RATE_LIMITED for the same messageId — if the user is no longer in the target chat, the operation may simply be stale by the time it could drain.

When both apply​

Heavy CRM-initiated workloads can hit either limit:

  • A flood of POST /crm/webhook calls hits the HTTP webhook rate limit (HTTP 429 + TOO_MANY_REQUESTS).
  • A flood of sends that drain slowly on the Mac — most often attachments, animation effects, reactions, and standalone stickers, but plain text counts too — can fill the automation queue (status callback with error.code: RATE_LIMITED).

The two limits are independent: hitting one does not exempt you from the other.

Other rate limits​

These don't fire on the typical CRM message-routing flow but are visible to marketplace OAuth callbacks and infrastructure probes:

SurfaceEndpointsLimitAction on exceeded
OAuth callbackGET /oauth/callback/crm, POST /oauth/callback/crm (CRM marketplace install flow)tunable per deploymentHTTP 429 with a JSON body.
HealthGET /health30 / IP / minuteHTTP 429 with a JSON body.
Health (PM2 probe)GET /health?pm2=15 / IP / minuteHTTP 429 with a JSON body.

If you build a marketplace integration, plan for HTTP 429 on the OAuth callback the same way you do for /crm/webhook.

  • HTTP Webhooks — the request/response contract including HTTP 429.
  • Error codes — full catalog including TOO_MANY_REQUESTS and RATE_LIMITED.