Message fields reference (v4)
Every field on a v4 multi-channel message object, plus the full status lifecycle and protocol (transport) states across iMessage, SMS, RCS, and WhatsApp
This is the field-by-field reference for the v4 message object
(api.blooio.com/v4). v4 is a multi-channel API — the same message shape covers
iMessage, SMS, RCS, and WhatsApp — so it adds a few transport values that don't
exist in v2. For the single-channel iMessage API, see the
v2 message fields reference.
Note
The v4 API is currently in beta. Field shapes are stable, but new
status/protocolvalues may be added as channels evolve — always handle unknown values defensively.
The message object
{
"id": "msg_018f7b2a1c3d7e4f9a2b0c1d2e3f4a5b",
"chat_id": "chat_abc123",
"channel_id": "ch_abc123",
"channel_type": "blooio",
"protocol": "imessage",
"direction": "outbound",
"type": "text",
"text": "Hello!",
"status": "delivered",
"provider_message_id": "p_9f8e...",
"reply_to_message_id": null,
"error": null,
"created_at": 1720992000000,
"updated_at": 1720992003000
}| Field | Type | Description |
|---|---|---|
id |
string | Unique message id, prefixed msg_. |
chat_id |
string | The chat this message belongs to (chat_). |
channel_id |
string | The sending/receiving channel (ch_). |
channel_type |
enum | blooio (iMessage), twilio, whatsapp_business, or rcs_business. |
protocol |
enum | Transport that carried the message — see Protocol states. |
direction |
enum | inbound or outbound. |
type |
string | Content type, e.g. text, media, poll. |
text |
string | null | Message body. null for media-only messages. |
status |
string | Delivery lifecycle state — see Status lifecycle. |
provider_message_id |
string | null | The upstream provider/device id, once assigned. |
reply_to_message_id |
string | null | The msg_ this message replies to, when it's an inline reply. |
error |
object | null | Structured error ({ code, message, ... }) when status is failed or protocol resolution failed. |
created_at |
int64 | Epoch milliseconds when the message was created. |
updated_at |
int64 | Epoch milliseconds of the last status/protocol update. |
The send endpoints return the message at the top level (not wrapped in
data) as a MessageSendResult, which adds routing hints like group_id,
hybrid, and fallback.
Status lifecycle
status describes where a message is in its delivery lifecycle, independent
of which channel or transport carried it.
| Status | Description |
|---|---|
queued |
Accepted and waiting to be handed to the channel. |
sent |
Handed off to the channel/provider. Protocol resolves around here. |
delivered |
A delivery receipt was received. |
read |
A read receipt was received (where the channel supports it). |
failed |
The message could not be delivered — see error. |
superseded |
The row was replaced (an idempotency-key retry loser, or a poll-vote supersession) and is not an independently deliverable message. |
Typical happy path:
queued → sent → delivered → readNote
Inbound messages surface through the unified event feed and webhooks with status
received. Lifecycle transitions are emitted asmessage.*events (message.sent,message.delivered,message.read,message.failed).
Protocol states
protocol records the transport that carried (or will carry) the message.
For blooio (iMessage) channels, Blooio picks the transport at send time and
resolves it shortly after; other channel types have a fixed transport.
Warning
protocolis nevernull. A freshly-accepted message starts atpendingand resolves to a concrete transport within seconds.
| Protocol | Meaning |
|---|---|
pending |
Accepted and dispatched; the wire service is not resolved yet. Transient — settles within seconds of sent. |
imessage |
Delivered over iMessage (blue bubble). |
rcs |
Delivered over RCS. |
sms |
Delivered over SMS/MMS (green bubble). |
whatsapp |
Sent over WhatsApp. |
unknown |
Accepted, but the transport could not be resolved before the tracking window closed (see error). |
How protocol relates to channel_type
For fixed-transport channels the protocol is known immediately; only blooio
(iMessage) sends start at pending while the device resolves the wire service.
channel_type |
Initial protocol |
Resolves to |
|---|---|---|
blooio |
pending |
imessage / rcs / sms (or unknown) |
twilio |
sms |
sms |
rcs_business |
rcs |
rcs |
whatsapp_business |
whatsapp |
whatsapp |
Reading protocol safely
Treat pending as "not yet known" and unknown as a terminal
"accepted but unconfirmed" state. Because v4 is multi-channel and evolving,
always keep a default branch for values you don't recognize.
switch (message.protocol) {
case "pending":
// Not resolved yet — re-read or wait for a message.* event.
break;
case "imessage":
case "rcs":
case "whatsapp":
// Rich transport confirmed.
break;
case "sms":
// SMS/MMS.
break;
case "unknown":
// Accepted, but transport never confirmed. Inspect `error`.
break;
default:
// Forward-compatible: handle new transports gracefully.
break;
}Next steps
- Message fields reference (v2) — single-channel iMessage API
- Message sending basics — chat IDs, options, quirks
- Webhooks — receive
message.*events in real time