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.
| Status | When | Body |
|---|---|---|
200 OK | Forwarded to the Mac. | { "status": "success", ... } |
400 Bad Request | Malformed request (missing required field, body too long). | { "error": "Missing required fields", "required": [...], "received": {...} } |
401 Unauthorized | Signature header present but invalid (only when signature verification is enabled on the deployment — see Signature verification). | (varies) |
404 Not Found | No Mac client connected for that locationId. | { "error": "Location not connected", "locationId", "message" } |
429 Too Many Requests | Per-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." } |
5xx | Internal 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.
{ "status": "delivered" }
{
"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
codeyou 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.
Related
- Error codes — the catalog.
- Rate limiting —
TOO_MANY_REQUESTS(HTTP 429) andRATE_LIMITED(status-update) semantics. - HTTP Webhooks — both webhook directions and full HTTP response shapes.