Tapbacks
Tapbacks are iMessage's inline reactions — the heart, thumbs-up, "haha", and friends that attach to a specific message bubble. Agents can send them, humans send them back, and message reads always carry the current live set.
Tapbacks follow Apple's semantics: one live tapback per sender per message. Sending a new tapback to a message you already reacted to replaces your previous one. When the human swaps or removes theirs, message reads and webhooks reflect it.
Send tapback POST
POST /reactionsReact to a message in one of your agent's conversations. Any message can be the target — the human's or the agent's own.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
message_id | UUID | Yes | The message being reacted to |
reaction | string | Yes | One of "love", "like", "dislike", "laugh", "emphasize", "question" |
part_index | integer | No | Part of a multi-part message to react to. Defaults to 0 |
Request example
Response (201)
If the agent already had a live tapback on that message part, it is replaced — exactly what the human sees happen on their device.
Error responses
| Status | Description |
|---|---|
| 400 | The conversation's identity is not enabled for iMessage, or the target message cannot accept reactions yet |
| 403 | The conversation's recipient is blocked by a contact rule |
| 404 | Message not found, or not visible to the caller |
| 409 | The recipient has disconnected from this agent and must reconnect through the router |
| 422 | Unknown reaction value or invalid part_index |
| 502 | Upstream delivery failure — safe to retry |
Receiving tapbacks
Tapbacks from humans arrive two ways:
- On message reads — every message object carries a
reactionsarray with the live tapbacks targeting it, oldest first. - As webhooks —
imessage.reaction_receivedfires when a human tapbacks one of your agent's messages.
Humans can react with any emoji, not just the classic six. Those arrive with reaction: "custom" and the literal emoji in custom_emoji:
Custom-emoji tapbacks are receive-only — sends accept the classic six.
When a human removes a tapback, it simply disappears from the message's reactions array on the next read. Removals do not fire a webhook.
Reaction object
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Reaction ID |
conversation_id | string (UUID) | The conversation containing the target message |
assignment_id | string (UUID) | The connection carrying the conversation |
target_message_id | string (UUID) | The message this tapback targets |
direction | string | "inbound" (from the human) or "outbound" (from the agent) |
reaction | string | "love", "like", "dislike", "laugh", "emphasize", "question", or "custom" |
custom_emoji | string | null | The literal emoji when reaction is "custom"; null for the classic six |
remote_number | string | The human's phone number (E.164) |
part_index | integer | Message part the tapback targets (0 for single-part messages) |
created_at | string (ISO 8601) | Creation timestamp |
updated_at | string (ISO 8601) | Last update timestamp |
The compact reaction entries embedded in a message's reactions array omit the conversation/assignment/target IDs (they're implied by the message) and the updated_at field.