Statuses
A message doesn’t always pass through every status. It can go straight from
accepted to delivered, and a message can stay at sent for good. Always act on the latest status rather than waiting for a particular sequence.
failed is normally final. Rarely, Blujay confirms afterwards that a failed message did go out, and it moves on to sent, delivered or read. Treat the newest status as the truth.
delivered and read are reported for direct chats. A group chat may not report them: a group message can stay at sent even when everyone has it. Don’t wait for delivered on a group message.
What each service reports
How far a message gets depends on the service that carried it.Which service carried the message
Every message has two service fields:
With Auto, both start as
null. That’s expected, not an error. service fills in as the message is sent.
Webhook payloads carry the same information in lowercase (imessage, rcs, sms). In webhooks, the field for what you asked for is called requested_service. From webhook version 2026-08-20 on, it holds the same value as preferred_service. See Webhook versions.
To choose a service yourself, see Send messages and iMessage, RCS or SMS.
Failures
A failed message carriesfailed_at, a failure object with a lowercase code and a readable reason, and retryable, on the message itself (GET /v1/messages/{message_id} and the list endpoints) and in the message.failed webhook alike. retryable: true means POST /v1/messages/{message_id}/retry will be accepted; false means it returns 409 RETRY_NOT_ALLOWED.
For five reasons the message also carries a failure_code that names the exact problem:
Every other failure has no
failure_code; failure.code still says what happened. To find failed messages, call GET /v1/messages?status=failed. In the message.failed webhook, versions 2026-08-01 and later carry the failure object, and 2026-09-02 and later also carry failure_code when there is one.
To send a failed message again, see Retry a failed message.
Degradations
Some features only exist on iMessage. When a direct message asks for one of them and goes out as SMS or RCS, Blujay still sends the text and lists what it dropped indegradations:
degradations is an empty array when nothing was dropped. Message reads and message webhooks carry the same entries.
Follow a message
You can follow a message with webhooks, by polling, or both.With webhooks (recommended)
Subscribe to the message events you need, and Blujay posts each status change to your server as it happens.message.delivered
- Webhooks are delivered at least once and can arrive out of order. Deduplicate on
event_id, and never replace a newer status with an older one. Use thesent_at,delivered_atandread_attimestamps to order them. message.acceptedis sent only for messages sent through the API.message.sent,message.delivered,message.readandmessage.failedalso cover messages your team sends from Blujay.- There’s no event for
sending. - The message object and the webhook payload carry the same tracking fields:
direction,sent_at,delivered_at,read_at,failed_at,failure, andsenderon inbound group messages. Webhooks tell you when they change; reads give you the current values.
By polling
GET /v1/messages/{message_id} returns the current status:
Webhooks are better than polling for anything after that, including the rare
failed that later becomes sent. To catch up on many messages at once, call GET /v1/messages?updated_after=2026-10-14T17:00:00.000Z with the time of your last sync. Reads count toward your read limit; see Rate limits.
Polling is fine for testing and for reconciling. In production, use webhooks and fall back to GET /v1/messages/{message_id} when an event seems missing.
Limitations
failure_codecovers five reasons you can act on. Every failed message also carries afailureobject with a lowercasecodeand a readablereason, the same one itsmessage.failedwebhook carries, andretryable, which says whetherPOST /v1/messages/{message_id}/retrywould be accepted.- SMS never reports
deliveredorread. Group chats may not report them either. sendinghas no webhook event.
Next steps
Webhooks overview
Get status changes pushed to your server.
Webhook events
Every message event and its payload.
Receive messages
Handle inbound texts, media and group replies.
Send messages
Start chats, send follow-ups and retry failures.