Skip to main content

Errors & Rate Limits

BlueSender surfaces errors through two channels visible to a CRM integration. Knowing which channel reports what is essential for writing a robust integration.

Error surfaces​

1. HTTP response from POST /crm/webhook​

Synchronous response when the CRM POSTs an outbound message.

StatusWhenBody
200 OKForwarded to the Mac.{ "status": "success", ... }
400 Bad RequestMalformed request (missing required field, body too long).{ "error": "Missing required fields", "required": [...], "received": {...} }
401 UnauthorizedSignature header present but invalid (only when signature verification is enabled on the deployment — see Signature verification).(varies)
404 Not FoundNo Mac client connected for that locationId.{ "error": "Location not connected", "locationId", "message" }
429 Too Many RequestsPer-locationId HTTP rate limit exceeded — or per-source-IP when locationId is missing/malformed.{ "error": "TOO_MANY_REQUESTS", "message": "Too many webhook requests for this location, please try again later." }
5xxInternal error during processing.(varies)

The error field on these bodies is a short label, not a structured error.code. Structured error.code values appear in the status-update channel below.

2. Status-update callback (PUT /conversations/messages/{messageId}/status)​

BlueSender makes this asynchronous callback to the CRM at two points in the outbound lifecycle. First, a pending callback fires immediately after the BlueSender backend has accepted the request and forwarded it toward the Mac (a backend-level acknowledgement, not a Mac-receipt acknowledgement). Then, a terminal delivered or failed callback fires once the Mac sends a status frame back.

Each callback is best-effort and is sent only when all three preconditions hold: BlueSender can resolve a message ID from the inbound request, the deployment has OAuth status callbacks configured, and (for the terminal callback) the Mac actually emits a status frame for the message. See Backend → CRM delivery for the resolution order and the OAuth requirement, and Authentication for the auth model. Sending an explicit messageId on POST /crm/webhook is strongly recommended.

success
{ "status": "delivered" }
failure
{
"status": "failed",
"error": {
"code": "TARGET_NOT_FOUND",
"type": "error",
"message": "Bubble not visible after scroll-into-view"
}
}

This is the primary place a CRM observes structured error.code values (e.g. CLIENT_NOT_CONNECTED, RATE_LIMITED, UI_AUTOMATION_DISABLED, STICKER_NOT_FEASIBLE, EMOJI_NOT_IN_RECENTS, etc.). See Error codes for the full catalog.

Code namespace conventions​

Error codes on the status-update channel are free-form strings — there is no closed enum and new codes can be added without a wire-version bump. The set of codes is documented in Error codes, but the contract is:

  • CRMs SHOULD tolerate unknown codes. Treat any code you don't recognize as transient + non-retryable, surface a generic "operation failed" indicator, and don't aggressively retry.
  • Codes are stable once introduced. A code documented today will not change meaning in a future release. Codes may be deprecated (with prior notice) but the wire form will not be reused for a different meaning.
  • Codes are SCREAMING_SNAKE_CASE strings. No prefixing scheme by feature — pick the most descriptive name.

Retry guidance​

The Error codes reference page lists each code with a recommended retry stance (yes / no / sometimes). For unknown codes, the safe default is don't retry — it's cheaper to lose a message than to retry a permanent failure forever.

  • Error codes — the catalog.
  • Rate limiting — TOO_MANY_REQUESTS (HTTP 429) and RATE_LIMITED (status-update) semantics.
  • HTTP Webhooks — both webhook directions and full HTTP response shapes.