imessage.* events you want.
The agent identity is the subscription owner whether its conversations use shared service or an attached dedicated line. The identity is the stable resource the events belong to. You can select iMessage events before enabling iMessage, and combine them with other notification families in the same subscription.
Received events include optional data.message.sender_access: "direct" when the message passed contact rules at receipt (including allowed by default), or "sponsored" when conversation sponsorship permits an originally default-filtered message. This is not sender trust or command permission. Unknown, system-generated, and outbound cases omit it. See per-message sender access.
Event types
Inbound traffic without ordinary or valid Companion permission emits no webhooks. Applicable contact-rule blocks still prevent Companion permission in their direction. Fan-out also pauses while the identity is paused or has
imessage_enabled: false. Tapback removals do not fire an event; the next message read simply no longer includes the removed tapback.
Eligible dedicated-line group imessage.received events can include optional top-level Companion metadata. Route its ordinary, initialization, and live phases by conversation scope, not by the last sender’s private session. Fetch the full snapshot before one combined initialization input. Reactions and tapbacks do not activate sponsorship.
Subscribing
imessage.sent, imessage.delivered, and imessage.delivery_failed to the same subscription to track outbound delivery. See Webhook Subscriptions for listing, updating, and deleting subscriptions, and Signing keys for verifying that deliveries came from Inkbox.
Payload envelope
Every delivery POSTs a JSON envelope:data carries message (for imessage.received and the delivery-lifecycle events) or reaction (for imessage.reaction_received), plus peer-resolution lists — and, on imessage.received when the subscription configures conversation context, an additive data.context block:
Reply thread metadata
Thedata.message object on received and delivery-lifecycle events includes nullable reply_to_message_id, thread_id, and thread_root_message_id. These fields describe message relationships in both 1:1 and group conversations. A non-null reply_to_message_id identifies a visible reply. An ordinary received or confirmed sent message can also have its own thread_id and itself as thread_root_message_id, even before anyone replies. A thread ID alone does not imply replies exist. A group reply also uses sender_number to identify its sender.
References can be unresolved or unavailable at event time, so a null parent does not necessarily mean an ordinary message. Re-read the message for its current metadata, or use its ID to retrieve the reply thread. Tolerate missing or null fields on older events. Reply threads use the existing message event types; ordinary chat messages are not inferred to be replies from their text.
If a send uses ordinary reply fallback, the resulting message has no native parent and does not belong to the requested target’s reply thread. Use the event’s actual message metadata rather than copying relationships from the original send request.
imessage.received
For a dedicated-line 1:1 conversation,data.message.remote_number can be a non-phone sender address such as sender@example.com. Preserve that string as returned and use conversation_id to read the conversation. Do not reject the event because the address is not E.164 or automatically reply to every received event. Non-phone conversations are receive-only; their messages use the same event type and envelope.
JSON
is_blocked field and add optional sender_access. Default-filtered messages can arrive through valid Companion sponsorship; applicable explicit blocks remain suppressed.
Group messages
An inbound group chat uses the sameimessage.received event. Its message has is_group: true, null assignment_id, the sender’s E.164 phone number in both sender_number and remote_number, and a best-known participant snapshot:
JSON
imessage.reaction_received
JSON
reaction can be any of the seven named values ("love", "like", "dislike", "laugh", "emphasize", "question", or "eyes") or "custom" with the literal inbound emoji in custom_emoji. Remember the replacement rule: a new tapback from the same human on the same message replaces their previous one, so treat the latest event as the current state for that sender.
An inbound group tapback uses the same event and target-message semantics. Its reaction has assignment_id: null, target_message_id identifies the exact message bubble, and remote_number identifies the participant who reacted. Adds and replacements emit this event; a removal clears the live reaction from later message reads without emitting a removal webhook.
Delivery lifecycle events
Delivery updates for outbound messages emit message-level events:imessage.sent when the message is accepted for delivery, then imessage.delivered when it reaches the recipient’s device, or imessage.delivery_failed if delivery fails. Only outbound messages produce these events, and only when the message as a whole changes status — per-recipient bookkeeping that doesn’t move the message’s own status does not fire.
Delivery-lifecycle events do not cover every failure before sending. For example, a queued reply whose target becomes unavailable has status: "error" and error_code: "imessage_reply_target_unavailable", but may not emit a delivery webhook. Poll Get message to observe every outcome.
A definitive rejection while the first message is still creating a new group can also fail before the delivery lifecycle begins. Re-read that message and its conversation to observe status: "error" and group_creation_status: "not_created", then send another message using the same conversation_id to retry.
The three payloads share one shape and differ only in event_type, the message’s status, and the error fields:
JSON
imessage.sent the message arrives with status: "sent", on imessage.delivered with status: "delivered", both with the error fields null. On imessage.delivery_failed the message’s status is "declined" or "error" and the error fields describe what went wrong.
For an outbound group event, assignment_id, remote_number, and sender_number are null, is_group is true, participants is the message’s participant snapshot, and recipients contains one entry per participant. The webhook is a message-level transition, so the aggregate group state is applied to those participant entries together.
Delivery semantics
- Deliveries are fire-and-forget HTTP POSTs; your response status is logged but does not affect message processing. Respond
2xxquickly and process asynchronously. - Each subscription on the identity receives its own POST per event, independently.
- When the subscription sets an
auth_token, each POST additionally carriesAuthorization: Bearer <token>alongside the signature headers — see Authenticating to your endpoint. - Verify deliveries with your signing key before trusting the payload.
Conversation context
When a subscription setscontext_config, imessage.received payloads gain an additive data.context object keyed by the configured classes (email, texts, calls). The texts class is conversation-scoped (the triggering conversation, with any matching SMS merged in); email and calls resolve contact-scoped history through the matched contact. imessage.reaction_received and delivery-status events never carry context.
The block shape — per-class fields, item shapes, transcript abridgment, skip reasons, and the 256 KB cap — is documented on the Mail webhooks page, and the configuration shape on the Webhook Subscriptions page.

