Webhooks
ModelsExpand Collapse
MessageEventV2 object { id, chat, direction, 12 more } Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead of is_from_me boolean
sender_handle: Full handle object for the sender
chat: Nested object with id, is_group, and owner_handle
- Message fields (
id, parts, effect, etc.) are at the top level, not nested in message
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=null
message.received: sent_at set, delivered_at=null, read_at=null
message.delivered: sent_at set, delivered_at set, read_at=null
message.read: sent_at set, delivered_at set, read_at set
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead ofis_from_mebooleansender_handle: Full handle object for the senderchat: Nested object withid,is_group, andowner_handle- Message fields (
id,parts,effect, etc.) are at the top level, not nested inmessage
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=nullmessage.received: sent_at set, delivered_at=null, read_at=nullmessage.delivered: sent_at set, delivered_at set, read_at=nullmessage.read: sent_at set, delivered_at set, read_at set
chat: object { id, health_status, is_group, owner_handle } Chat information
Chat information
health_status: object { doc_url, status, updated_at } [BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
[BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
status: "HEALTHY" or "AT_RISK" or "CRITICAL" or "OPTED_OUT"Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
direction: "inbound" or "outbound"Message direction - “outbound” if sent by you, “inbound” if received
Message direction - “outbound” if sent by you, “inbound” if received
parts: array of SchemasTextPartResponse { type, value, mention, 3 more } or SchemasMediaPartResponse { id, filename, mime_type, 3 more } or object { type, value } or 2 moreMessage parts (text and/or media)
Message parts (text and/or media)
SchemasTextPartResponse object { type, value, mention, 3 more } A text message part
A text message part
DEPRECATED: Use mentions instead. Handle (E.164 phone number or Apple ID email)
of the first mention on this part. A part may carry several mentions; this
field shows only the first in value order, so it cannot be used to determine
whether a given participant was mentioned. null when the part carries no mention.
DEPRECATED: Use mentions[].range instead. Character range [start, end) in
value highlighted as the first mention only. null when the range was
omitted (the whole value is highlighted) or the part carries no mention.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
mentions: optional array of object { handle, is_me, range } Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Text decorations applied to character ranges in the value
Text decorations applied to character ranges in the value
Character range [start, end) in the value string where the decoration applies.
start is inclusive, end is exclusive.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
IMessageApp object { app, layout, type, 2 more } An iMessage app card part.
An iMessage app card part.
When the message was delivered. Null if not yet delivered.
preferred_service: optional "iMessage" or "SMS" or "RCS" or "auto"Preferred messaging service type. Includes “auto” for default fallback behavior.
Preferred messaging service type. Includes “auto” for default fallback behavior.
Present only when this message was recovered by reconciliation rather than delivered live, and set to the time of that recovery. The field is omitted entirely for normally-delivered messages, which is the overwhelming majority. When present, expect sent_at to be substantially earlier than delivery of this event: the message is genuine but is arriving late and out of real-time order, so treat it as history rather than as a live inbound (for example, suppress auto-replies).
MessagePayload object { id, created_at, delivered_at, 10 more } Message content nested within webhook events
Message content nested within webhook events
parts: optional array of SchemasTextPartResponse { type, value, mention, 3 more } or SchemasMediaPartResponse { id, filename, mime_type, 3 more } or object { type, value } or 2 moreMessage content parts (text and/or media)
Message content parts (text and/or media)
SchemasTextPartResponse object { type, value, mention, 3 more } A text message part
A text message part
DEPRECATED: Use mentions instead. Handle (E.164 phone number or Apple ID email)
of the first mention on this part. A part may carry several mentions; this
field shows only the first in value order, so it cannot be used to determine
whether a given participant was mentioned. null when the part carries no mention.
DEPRECATED: Use mentions[].range instead. Character range [start, end) in
value highlighted as the first mention only. null when the range was
omitted (the whole value is highlighted) or the part carries no mention.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
mentions: optional array of object { handle, is_me, range } Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Text decorations applied to character ranges in the value
Text decorations applied to character ranges in the value
Character range [start, end) in the value string where the decoration applies.
start is inclusive, end is exclusive.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
SchemasIMessageAppPartResponse object { app, layout, type, 2 more } An iMessage app card part.
An iMessage app card part.
Present only when this message was recovered by reconciliation rather than delivered live, and set to the time of that recovery. The field is omitted entirely for normally-delivered messages, which is the overwhelming majority. When present, expect sent_at to be substantially earlier than delivery of this event: the message is genuine but is arriving late and out of real-time order, so treat it as history rather than as a live inbound (for example, suppress auto-replies).
ReactionEventBase object { is_from_me, reaction_type, chat_id, 9 more }
Whether this reaction was from the owner of the phone number (true) or from someone else (false)
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question.
Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field.
Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question. Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field. Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
The actual emoji when reaction_type is “custom”. Null for standard tapbacks.
DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.
Index of the message part that was reacted to (0-based)
Identifier for this reaction. Pass it to
PATCH /v3/messages/{messageId}/reactions/{reactionId} to move a sticker.
Stickers stack, so this is what distinguishes one sticker from another on the
same message.
SchemasTextPartResponse object { type, value, mention, 3 more } A text message part
A text message part
DEPRECATED: Use mentions instead. Handle (E.164 phone number or Apple ID email)
of the first mention on this part. A part may carry several mentions; this
field shows only the first in value order, so it cannot be used to determine
whether a given participant was mentioned. null when the part carries no mention.
DEPRECATED: Use mentions[].range instead. Character range [start, end) in
value highlighted as the first mention only. null when the range was
omitted (the whole value is highlighted) or the part carries no mention.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
mentions: optional array of object { handle, is_me, range } Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Text decorations applied to character ranges in the value
Text decorations applied to character ranges in the value
Character range [start, end) in the value string where the decoration applies.
start is inclusive, end is exclusive.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
MessageSentWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for message.sent events (2026-02-03 format)
Complete webhook payload for message.sent events (2026-02-03 format)
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead of is_from_me boolean
sender_handle: Full handle object for the sender
chat: Nested object with id, is_group, and owner_handle
- Message fields (
id, parts, effect, etc.) are at the top level, not nested in message
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=null
message.received: sent_at set, delivered_at=null, read_at=null
message.delivered: sent_at set, delivered_at set, read_at=null
message.read: sent_at set, delivered_at set, read_at set
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead ofis_from_mebooleansender_handle: Full handle object for the senderchat: Nested object withid,is_group, andowner_handle- Message fields (
id,parts,effect, etc.) are at the top level, not nested inmessage
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=nullmessage.received: sent_at set, delivered_at=null, read_at=nullmessage.delivered: sent_at set, delivered_at set, read_at=nullmessage.read: sent_at set, delivered_at set, read_at set
chat: object { id, health_status, is_group, owner_handle } Chat information
Chat information
health_status: object { doc_url, status, updated_at } [BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
[BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
status: "HEALTHY" or "AT_RISK" or "CRITICAL" or "OPTED_OUT"Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
direction: "inbound" or "outbound"Message direction - “outbound” if sent by you, “inbound” if received
Message direction - “outbound” if sent by you, “inbound” if received
parts: array of SchemasTextPartResponse { type, value, mention, 3 more } or SchemasMediaPartResponse { id, filename, mime_type, 3 more } or object { type, value } or 2 moreMessage parts (text and/or media)
Message parts (text and/or media)
SchemasTextPartResponse object { type, value, mention, 3 more } A text message part
A text message part
DEPRECATED: Use mentions instead. Handle (E.164 phone number or Apple ID email)
of the first mention on this part. A part may carry several mentions; this
field shows only the first in value order, so it cannot be used to determine
whether a given participant was mentioned. null when the part carries no mention.
DEPRECATED: Use mentions[].range instead. Character range [start, end) in
value highlighted as the first mention only. null when the range was
omitted (the whole value is highlighted) or the part carries no mention.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
mentions: optional array of object { handle, is_me, range } Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Text decorations applied to character ranges in the value
Text decorations applied to character ranges in the value
Character range [start, end) in the value string where the decoration applies.
start is inclusive, end is exclusive.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
IMessageApp object { app, layout, type, 2 more } An iMessage app card part.
An iMessage app card part.
When the message was delivered. Null if not yet delivered.
preferred_service: optional "iMessage" or "SMS" or "RCS" or "auto"Preferred messaging service type. Includes “auto” for default fallback behavior.
Preferred messaging service type. Includes “auto” for default fallback behavior.
Present only when this message was recovered by reconciliation rather than delivered live, and set to the time of that recovery. The field is omitted entirely for normally-delivered messages, which is the overwhelming majority. When present, expect sent_at to be substantially earlier than delivery of this event: the message is genuine but is arriving late and out of real-time order, so treat it as history rather than as a live inbound (for example, suppress auto-replies).
MessageReceivedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for message.received events (2026-02-03 format)
Complete webhook payload for message.received events (2026-02-03 format)
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead of is_from_me boolean
sender_handle: Full handle object for the sender
chat: Nested object with id, is_group, and owner_handle
- Message fields (
id, parts, effect, etc.) are at the top level, not nested in message
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=null
message.received: sent_at set, delivered_at=null, read_at=null
message.delivered: sent_at set, delivered_at set, read_at=null
message.read: sent_at set, delivered_at set, read_at set
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead ofis_from_mebooleansender_handle: Full handle object for the senderchat: Nested object withid,is_group, andowner_handle- Message fields (
id,parts,effect, etc.) are at the top level, not nested inmessage
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=nullmessage.received: sent_at set, delivered_at=null, read_at=nullmessage.delivered: sent_at set, delivered_at set, read_at=nullmessage.read: sent_at set, delivered_at set, read_at set
chat: object { id, health_status, is_group, owner_handle } Chat information
Chat information
health_status: object { doc_url, status, updated_at } [BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
[BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
status: "HEALTHY" or "AT_RISK" or "CRITICAL" or "OPTED_OUT"Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
direction: "inbound" or "outbound"Message direction - “outbound” if sent by you, “inbound” if received
Message direction - “outbound” if sent by you, “inbound” if received
parts: array of SchemasTextPartResponse { type, value, mention, 3 more } or SchemasMediaPartResponse { id, filename, mime_type, 3 more } or object { type, value } or 2 moreMessage parts (text and/or media)
Message parts (text and/or media)
SchemasTextPartResponse object { type, value, mention, 3 more } A text message part
A text message part
DEPRECATED: Use mentions instead. Handle (E.164 phone number or Apple ID email)
of the first mention on this part. A part may carry several mentions; this
field shows only the first in value order, so it cannot be used to determine
whether a given participant was mentioned. null when the part carries no mention.
DEPRECATED: Use mentions[].range instead. Character range [start, end) in
value highlighted as the first mention only. null when the range was
omitted (the whole value is highlighted) or the part carries no mention.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
mentions: optional array of object { handle, is_me, range } Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Text decorations applied to character ranges in the value
Text decorations applied to character ranges in the value
Character range [start, end) in the value string where the decoration applies.
start is inclusive, end is exclusive.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
IMessageApp object { app, layout, type, 2 more } An iMessage app card part.
An iMessage app card part.
When the message was delivered. Null if not yet delivered.
preferred_service: optional "iMessage" or "SMS" or "RCS" or "auto"Preferred messaging service type. Includes “auto” for default fallback behavior.
Preferred messaging service type. Includes “auto” for default fallback behavior.
Present only when this message was recovered by reconciliation rather than delivered live, and set to the time of that recovery. The field is omitted entirely for normally-delivered messages, which is the overwhelming majority. When present, expect sent_at to be substantially earlier than delivery of this event: the message is genuine but is arriving late and out of real-time order, so treat it as history rather than as a live inbound (for example, suppress auto-replies).
MessageReadWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for message.read events (2026-02-03 format)
Complete webhook payload for message.read events (2026-02-03 format)
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead of is_from_me boolean
sender_handle: Full handle object for the sender
chat: Nested object with id, is_group, and owner_handle
- Message fields (
id, parts, effect, etc.) are at the top level, not nested in message
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=null
message.received: sent_at set, delivered_at=null, read_at=null
message.delivered: sent_at set, delivered_at set, read_at=null
message.read: sent_at set, delivered_at set, read_at set
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead ofis_from_mebooleansender_handle: Full handle object for the senderchat: Nested object withid,is_group, andowner_handle- Message fields (
id,parts,effect, etc.) are at the top level, not nested inmessage
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=nullmessage.received: sent_at set, delivered_at=null, read_at=nullmessage.delivered: sent_at set, delivered_at set, read_at=nullmessage.read: sent_at set, delivered_at set, read_at set
chat: object { id, health_status, is_group, owner_handle } Chat information
Chat information
health_status: object { doc_url, status, updated_at } [BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
[BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
status: "HEALTHY" or "AT_RISK" or "CRITICAL" or "OPTED_OUT"Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
direction: "inbound" or "outbound"Message direction - “outbound” if sent by you, “inbound” if received
Message direction - “outbound” if sent by you, “inbound” if received
parts: array of SchemasTextPartResponse { type, value, mention, 3 more } or SchemasMediaPartResponse { id, filename, mime_type, 3 more } or object { type, value } or 2 moreMessage parts (text and/or media)
Message parts (text and/or media)
SchemasTextPartResponse object { type, value, mention, 3 more } A text message part
A text message part
DEPRECATED: Use mentions instead. Handle (E.164 phone number or Apple ID email)
of the first mention on this part. A part may carry several mentions; this
field shows only the first in value order, so it cannot be used to determine
whether a given participant was mentioned. null when the part carries no mention.
DEPRECATED: Use mentions[].range instead. Character range [start, end) in
value highlighted as the first mention only. null when the range was
omitted (the whole value is highlighted) or the part carries no mention.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
mentions: optional array of object { handle, is_me, range } Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Text decorations applied to character ranges in the value
Text decorations applied to character ranges in the value
Character range [start, end) in the value string where the decoration applies.
start is inclusive, end is exclusive.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
IMessageApp object { app, layout, type, 2 more } An iMessage app card part.
An iMessage app card part.
When the message was delivered. Null if not yet delivered.
preferred_service: optional "iMessage" or "SMS" or "RCS" or "auto"Preferred messaging service type. Includes “auto” for default fallback behavior.
Preferred messaging service type. Includes “auto” for default fallback behavior.
Present only when this message was recovered by reconciliation rather than delivered live, and set to the time of that recovery. The field is omitted entirely for normally-delivered messages, which is the overwhelming majority. When present, expect sent_at to be substantially earlier than delivery of this event: the message is genuine but is arriving late and out of real-time order, so treat it as history rather than as a live inbound (for example, suppress auto-replies).
MessageDeliveredWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for message.delivered events (2026-02-03 format)
Complete webhook payload for message.delivered events (2026-02-03 format)
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead of is_from_me boolean
sender_handle: Full handle object for the sender
chat: Nested object with id, is_group, and owner_handle
- Message fields (
id, parts, effect, etc.) are at the top level, not nested in message
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=null
message.received: sent_at set, delivered_at=null, read_at=null
message.delivered: sent_at set, delivered_at set, read_at=null
message.read: sent_at set, delivered_at set, read_at set
Unified payload for message webhooks when using webhook_version: "2026-02-03".
This schema is used for message.sent, message.received, message.delivered, and message.read
events when the subscription URL includes ?version=2026-02-03.
Key differences from V1 (2025-01-01):
direction: “inbound” or “outbound” instead ofis_from_mebooleansender_handle: Full handle object for the senderchat: Nested object withid,is_group, andowner_handle- Message fields (
id,parts,effect, etc.) are at the top level, not nested inmessage
Timestamps indicate the message state:
message.sent: sent_at set, delivered_at=null, read_at=nullmessage.received: sent_at set, delivered_at=null, read_at=nullmessage.delivered: sent_at set, delivered_at set, read_at=nullmessage.read: sent_at set, delivered_at set, read_at set
chat: object { id, health_status, is_group, owner_handle } Chat information
Chat information
health_status: object { doc_url, status, updated_at } [BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
[BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
status: "HEALTHY" or "AT_RISK" or "CRITICAL" or "OPTED_OUT"Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
direction: "inbound" or "outbound"Message direction - “outbound” if sent by you, “inbound” if received
Message direction - “outbound” if sent by you, “inbound” if received
parts: array of SchemasTextPartResponse { type, value, mention, 3 more } or SchemasMediaPartResponse { id, filename, mime_type, 3 more } or object { type, value } or 2 moreMessage parts (text and/or media)
Message parts (text and/or media)
SchemasTextPartResponse object { type, value, mention, 3 more } A text message part
A text message part
DEPRECATED: Use mentions instead. Handle (E.164 phone number or Apple ID email)
of the first mention on this part. A part may carry several mentions; this
field shows only the first in value order, so it cannot be used to determine
whether a given participant was mentioned. null when the part carries no mention.
DEPRECATED: Use mentions[].range instead. Character range [start, end) in
value highlighted as the first mention only. null when the range was
omitted (the whole value is highlighted) or the part carries no mention.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
mentions: optional array of object { handle, is_me, range } Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Every mention on this part, in the order they appear in value. null when the
part carries no mention. A part can carry several mentions of different people —
check is_me to tell whether this line was one of them.
Only iMessage carries mentions. On a received message this is populated when the
sender was on iMessage; SMS and RCS have no way to mark a mention, so a message
from an SMS or RCS participant arrives as plain text with mentions null, even in
a group where other participants are on iMessage.
Text decorations applied to character ranges in the value
Text decorations applied to character ranges in the value
Character range [start, end) in the value string where the decoration applies.
start is inclusive, end is exclusive.
Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.
IMessageApp object { app, layout, type, 2 more } An iMessage app card part.
An iMessage app card part.
When the message was delivered. Null if not yet delivered.
preferred_service: optional "iMessage" or "SMS" or "RCS" or "auto"Preferred messaging service type. Includes “auto” for default fallback behavior.
Preferred messaging service type. Includes “auto” for default fallback behavior.
Present only when this message was recovered by reconciliation rather than delivered live, and set to the time of that recovery. The field is omitted entirely for normally-delivered messages, which is the overwhelming majority. When present, expect sent_at to be substantially earlier than delivery of this event: the message is genuine but is arriving late and out of real-time order, so treat it as history rather than as a live inbound (for example, suppress auto-replies).
MessageFailedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for message.failed events
Complete webhook payload for message.failed events
data: object { code, failed_at, chat_id, 5 more } Error details for message.failed webhook events.
See WebhookErrorCode for the full error code reference.
In rare cases the message can still be delivered after this event fires — a message.delivered webhook for the same message ID may follow.
Error details for message.failed webhook events. See WebhookErrorCode for the full error code reference.
In rare cases the message can still be delivered after this event fires — a message.delivered webhook for the same message ID may follow.
Error codes in webhook failure events. The possible set varies by event: message.failed and poll.failed can carry 3007, 4001, 4002, 4005, 4006, 4007, or 4008; the group update failure events (chat.group_name_update_failed, chat.group_icon_update_failed) carry 3007 or 4001; chat.background_update_failed carries 1005, 2011, 4001, or 5002.
Opaque diagnostic code identifying the specific failure class within code.
Values are not enumerated and may change without notice — log it and include
it in support requests, but do not branch on it.
preferred_service: optional "iMessage" or "SMS" or "RCS" or "auto"Preferred messaging service type. Includes “auto” for default fallback behavior.
Preferred messaging service type. Includes “auto” for default fallback behavior.
MessageEditedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for message.edited events (2026-02-03 format only)
Complete webhook payload for message.edited events (2026-02-03 format only)
data: object { id, chat, direction, 4 more } Payload for message.edited events (2026-02-03 format).
Describes which part of a message was edited and when. Only text parts can be edited.
Only available for subscriptions using webhook_version: "2026-02-03".
Payload for message.edited events (2026-02-03 format).
Describes which part of a message was edited and when. Only text parts can be edited.
Only available for subscriptions using webhook_version: "2026-02-03".
chat: object { id, health_status, is_group, owner_handle } Chat context
Chat context
health_status: object { doc_url, status, updated_at } [BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
[BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
status: "HEALTHY" or "AT_RISK" or "CRITICAL" or "OPTED_OUT"Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
direction: "outbound" or "inbound"“outbound” if you sent the original message, “inbound” if you received it
“outbound” if you sent the original message, “inbound” if you received it
True when the edited message is on a zero-day-retention line. Behavior differs by direction: on an outbound edit, part.text is empty — you already saw the real edited text once, synchronously, in the edit API response, and Linq never persists it. On an inbound edit, part.text is still the real text as received; zero-day-retention only means Linq never persists it.
ReactionAddedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for reaction.added events
Complete webhook payload for reaction.added events
Payload for reaction.added webhook events
Payload for reaction.added webhook events
Whether this reaction was from the owner of the phone number (true) or from someone else (false)
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question.
Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field.
Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question. Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field. Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
The actual emoji when reaction_type is “custom”. Null for standard tapbacks.
DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.
Index of the message part that was reacted to (0-based)
Identifier for this reaction. Pass it to
PATCH /v3/messages/{messageId}/reactions/{reactionId} to move a sticker.
Stickers stack, so this is what distinguishes one sticker from another on the
same message.
ReactionRemovedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for reaction.removed events
Complete webhook payload for reaction.removed events
Payload for reaction.removed webhook events
Payload for reaction.removed webhook events
Whether this reaction was from the owner of the phone number (true) or from someone else (false)
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question.
Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field.
Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question. Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field. Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
The actual emoji when reaction_type is “custom”. Null for standard tapbacks.
DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.
Index of the message part that was reacted to (0-based)
Identifier for this reaction. Pass it to
PATCH /v3/messages/{messageId}/reactions/{reactionId} to move a sticker.
Stickers stack, so this is what distinguishes one sticker from another on the
same message.
PollReceivedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.received events
Complete webhook payload for poll.received events
data: object { chat, created_at, direction, 7 more } Payload for poll.received — a poll created by someone else and delivered to your line.
Carries the full poll snapshot (options, no voters yet) at receipt time.
Payload for poll.received — a poll created by someone else and delivered to your line. Carries the full poll snapshot (options, no voters yet) at receipt time.
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
poll: object { options, total_voters }
options: array of object { can_be_edited, creator_handle, option_id, 2 more }
True when your line has zero-day-retention enabled. Unlike other poll webhooks, option text here is still the real, unstripped text as received — Linq never persists it in the database, but this webhook fires from the live inbound event, not a database read, so this is the one place it’s shown.
PollSentWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.sent events
Complete webhook payload for poll.sent events
data: object { chat, created_at, direction, 9 more } Payload for poll.sent, poll.delivered, and poll.read webhook events. Timestamps indicate
state (null = not yet happened): sent → sent_at; delivered → +delivered_at; read → +read_at.
Payload for poll.sent, poll.delivered, and poll.read webhook events. Timestamps indicate state (null = not yet happened): sent → sent_at; delivered → +delivered_at; read → +read_at.
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
poll: object { options, total_voters }
options: array of object { can_be_edited, creator_handle, option_id, 2 more }
True when this poll was sent on a zero-day-retention line. Every option’s text is empty in that case — Linq never persists poll option text, so there is nothing to include here. The real text was only ever shown once, synchronously, in the API response when the poll was created or added to.
PollDeliveredWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.delivered events
Complete webhook payload for poll.delivered events
data: object { chat, created_at, direction, 9 more } Payload for poll.sent, poll.delivered, and poll.read webhook events. Timestamps indicate
state (null = not yet happened): sent → sent_at; delivered → +delivered_at; read → +read_at.
Payload for poll.sent, poll.delivered, and poll.read webhook events. Timestamps indicate state (null = not yet happened): sent → sent_at; delivered → +delivered_at; read → +read_at.
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
poll: object { options, total_voters }
options: array of object { can_be_edited, creator_handle, option_id, 2 more }
True when this poll was sent on a zero-day-retention line. Every option’s text is empty in that case — Linq never persists poll option text, so there is nothing to include here. The real text was only ever shown once, synchronously, in the API response when the poll was created or added to.
PollReadWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.read events
Complete webhook payload for poll.read events
data: object { chat, created_at, direction, 9 more } Payload for poll.sent, poll.delivered, and poll.read webhook events. Timestamps indicate
state (null = not yet happened): sent → sent_at; delivered → +delivered_at; read → +read_at.
Payload for poll.sent, poll.delivered, and poll.read webhook events. Timestamps indicate state (null = not yet happened): sent → sent_at; delivered → +delivered_at; read → +read_at.
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
poll: object { options, total_voters }
options: array of object { can_be_edited, creator_handle, option_id, 2 more }
True when this poll was sent on a zero-day-retention line. Every option’s text is empty in that case — Linq never persists poll option text, so there is nothing to include here. The real text was only ever shown once, synchronously, in the API response when the poll was created or added to.
PollUpdatedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.updated events
Complete webhook payload for poll.updated events
data: object { added_options, chat, direction, 4 more } Payload for poll.updated (option(s) added — add-only).
Payload for poll.updated (option(s) added — add-only).
added_options: array of object { can_be_edited, creator_handle, option_id, 2 more } Only the options this update added — never the ones the poll already had. Fetch the poll to read its full option set.
Only the options this update added — never the ones the poll already had. Fetch the poll to read its full option set.
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
Your line — the one that received or sent this update. Always present. On an inbound
update this is NOT who added the option: use added_options[].creator_handle for
that, which will be the remote participant.
Your line — the one that received or sent this update. Always present. On an inbound
update this is NOT who added the option: use added_options[].creator_handle for
that, which will be the remote participant.
True when zero-day-retention applies to this update. Behavior differs by direction: on an inbound update, added_options[].text is the real text a participant just added; on an outbound update, it is empty — you already saw the real text once, synchronously, in the API response when you made the add, and this webhook is built from a database read, which never stored it.
PollFailedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.failed events
Complete webhook payload for poll.failed events
data: object { chat, direction, error, 6 more } Payload for poll.failed — an outbound poll (or poll action) that failed to send. Carries the
poll snapshot at failure time plus the error and when it failed.
Payload for poll.failed — an outbound poll (or poll action) that failed to send. Carries the poll snapshot at failure time plus the error and when it failed.
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
error: object { code, message }
Error codes in webhook failure events. The possible set varies by event: message.failed and poll.failed can carry 3007, 4001, 4002, 4005, 4006, 4007, or 4008; the group update failure events (chat.group_name_update_failed, chat.group_icon_update_failed) carry 3007 or 4001; chat.background_update_failed carries 1005, 2011, 4001, or 5002.
poll: object { options, total_voters }
options: array of object { can_be_edited, creator_handle, option_id, 2 more }
PollVoteAddedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.vote.added events
Complete webhook payload for poll.vote.added events
data: object { chat, direction, message_id, 4 more } Payload for poll.vote.added and poll.vote.removed (one option toggled).
Payload for poll.vote.added and poll.vote.removed (one option toggled).
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
True when this poll is on a zero-day-retention line. Votes are unaffected by zero-day-retention — a vote choice is always persisted and delivered regardless — this flag is informational only, telling you why this poll’s other webhooks (poll.sent, poll.updated, etc.) may carry empty option text.
PollVoteRemovedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.vote.removed events
Complete webhook payload for poll.vote.removed events
data: object { chat, direction, message_id, 4 more } Payload for poll.vote.added and poll.vote.removed (one option toggled).
Payload for poll.vote.added and poll.vote.removed (one option toggled).
chat: object { id, is_group, owner_handle } Chat info for poll webhook events.
Chat info for poll webhook events.
True when this poll is on a zero-day-retention line. Votes are unaffected by zero-day-retention — a vote choice is always persisted and delivered regardless — this flag is informational only, telling you why this poll’s other webhooks (poll.sent, poll.updated, etc.) may carry empty option text.
PollReactionAddedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for poll.reaction.added events
Complete webhook payload for poll.reaction.added events
Payload for poll.reaction.added — a reaction on a poll message. Same shape as
reaction.added; message_id is the poll-definition message’s ID. Poll reactions are
stickers, which iMessage cannot remove, so there is no removal counterpart.
Payload for poll.reaction.added — a reaction on a poll message. Same shape as
reaction.added; message_id is the poll-definition message’s ID. Poll reactions are
stickers, which iMessage cannot remove, so there is no removal counterpart.
Whether this reaction was from the owner of the phone number (true) or from someone else (false)
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question.
Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field.
Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
Type of reaction. Standard iMessage tapbacks are love, like, dislike, laugh, emphasize, question. Custom emoji reactions have type “custom” with the actual emoji in the custom_emoji field. Sticker reactions have type “sticker” with sticker attachment details in the sticker field.
The actual emoji when reaction_type is “custom”. Null for standard tapbacks.
DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.
Index of the message part that was reacted to (0-based)
Identifier for this reaction. Pass it to
PATCH /v3/messages/{messageId}/reactions/{reactionId} to move a sticker.
Stickers stack, so this is what distinguishes one sticker from another on the
same message.
ParticipantAddedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for participant.added events
Complete webhook payload for participant.added events
data: object { handle, added_at, chat_id, participant } Payload for participant.added webhook events
Payload for participant.added webhook events
ParticipantRemovedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for participant.removed events
Complete webhook payload for participant.removed events
data: object { handle, chat_id, participant, removed_at } Payload for participant.removed webhook events
Payload for participant.removed webhook events
ChatCreatedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.created events
Complete webhook payload for chat.created events
data: object { id, created_at, display_name, 5 more } Payload for chat.created webhook events. Matches GET /v3/chats/{chatId} response.
Payload for chat.created webhook events. Matches GET /v3/chats/{chatId} response.
Display name for the chat. Defaults to a comma-separated list of recipient handles. Can be updated for group chats.
List of chat participants with full handle details. Always contains at least two handles (your phone number and the other participant).
List of chat participants with full handle details. Always contains at least two handles (your phone number and the other participant).
health_status: object { doc_url, status, updated_at } [BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
[BETA] Current health for a chat. Always present — chats start at HEALTHY and may shift based on engagement and delivery signals on the conversation. Many AT_RISK or CRITICAL chats on a single line increase the risk of line flagging.
Switch on status to surface chat and line health in your UI — the enum is the long-term contract. Each status carries a doc_url that deep-links to the relevant section of the Chat Health guide. To gate a send, act on the response rather than the status: a 403 is the authoritative answer.
See the Chat Health guide for what each status means and how to react.
status: "HEALTHY" or "AT_RISK" or "CRITICAL" or "OPTED_OUT"Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
Current health bucket for the chat. See the Chat Health guide for what each value means and how to react. doc_url deep-links to the relevant section.
OPTED_OUT — the recipient sent STOP, UNSUBSCRIBE, OPTOUT, CANCEL, END, or QUIT.
The keyword must be the whole trimmed message, never part of a longer one: STOP counts, please stop
does not. Most keywords must match exactly, including case. OPT OUT is the exception — it matches in any
casing, with or without the space or a hyphen, so opt out, Opt-Out and optout all count. It clears as
soon as they reply again: any later message from them that is not itself an opt-out keyword opts them back
in immediately — a reply in any conversation with you counts, the same way the block does.
OPTED_OUT marks only the conversation the keyword arrived in. The block below is wider than the mark, so
a conversation still reading HEALTHY can be blocked as well — gate on the 403, not on the status.
Group threads are never marked and are never blocked.
Linq enforces this: while a recipient is opted out, every send to them is rejected with 403 (error code
2024) before the message is queued, across every chat and every line on your account. Nothing is
delivered, including a final courtesy message — to send one, set override_optout: true on that single
request.
ChatGroupNameUpdatedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.group_name_updated events
Complete webhook payload for chat.group_name_updated events
data: object { chat_id, updated_at, changed_by_handle, 2 more } Payload for chat.group_name_updated webhook events
Payload for chat.group_name_updated webhook events
ChatGroupIconUpdatedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.group_icon_updated events
Complete webhook payload for chat.group_icon_updated events
data: object { chat_id, updated_at, changed_by_handle, 2 more } Payload for chat.group_icon_updated webhook events
Payload for chat.group_icon_updated webhook events
ChatGroupNameUpdateFailedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.group_name_update_failed events
Complete webhook payload for chat.group_name_update_failed events
data: object { chat_id, error_code, failed_at } Error details for chat.group_name_update_failed webhook events.
See WebhookErrorCode for the full error code reference.
Error details for chat.group_name_update_failed webhook events. See WebhookErrorCode for the full error code reference.
Error codes in webhook failure events. The possible set varies by event: message.failed and poll.failed can carry 3007, 4001, 4002, 4005, 4006, 4007, or 4008; the group update failure events (chat.group_name_update_failed, chat.group_icon_update_failed) carry 3007 or 4001; chat.background_update_failed carries 1005, 2011, 4001, or 5002.
ChatGroupIconUpdateFailedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.group_icon_update_failed events
Complete webhook payload for chat.group_icon_update_failed events
data: object { chat_id, error_code, failed_at } Error details for chat.group_icon_update_failed webhook events.
See WebhookErrorCode for the full error code reference.
Error details for chat.group_icon_update_failed webhook events. See WebhookErrorCode for the full error code reference.
Error codes in webhook failure events. The possible set varies by event: message.failed and poll.failed can carry 3007, 4001, 4002, 4005, 4006, 4007, or 4008; the group update failure events (chat.group_name_update_failed, chat.group_icon_update_failed) carry 3007 or 4001; chat.background_update_failed carries 1005, 2011, 4001, or 5002.
ChatTypingIndicatorStartedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.typing_indicator.started events
Complete webhook payload for chat.typing_indicator.started events
ChatTypingIndicatorStoppedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.typing_indicator.stopped events
Complete webhook payload for chat.typing_indicator.stopped events
ChatBackgroundUpdatedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.background_updated events
Complete webhook payload for chat.background_updated events
data: object { chat, actor_handle, background } Payload for chat.background_updated webhook events.
Payload for chat.background_updated webhook events.
chat: object { id, is_group, owner_handle } Chat information
Chat information
background: optional object { type, image_url, shades, 2 more } A chat transcript background. Fields are populated per type.
A chat transcript background. Fields are populated per type.
Photo: a hosted URL for the background image, whether you set it or a
participant did. Apple stores the image, not the URL it came from, so the
image is re-hosted and this is our URL rather than the one you supplied.
null only if the image could not be hosted.
ChatBackgroundUpdateFailedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for chat.background_update_failed events
Complete webhook payload for chat.background_update_failed events
data: object { chat_id, error_code, failed_at } Error details for chat.background_update_failed webhook events.
See WebhookErrorCode for the full error code reference.
Error details for chat.background_update_failed webhook events. See WebhookErrorCode for the full error code reference.
Error codes in webhook failure events. The possible set varies by event: message.failed and poll.failed can carry 3007, 4001, 4002, 4005, 4006, 4007, or 4008; the group update failure events (chat.group_name_update_failed, chat.group_icon_update_failed) carry 3007 or 4001; chat.background_update_failed carries 1005, 2011, 4001, or 5002.
ContactCardReceivedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for contact_card.received events
Complete webhook payload for contact_card.received events
data: object { first_name, last_name, owner_handle, 2 more } Payload for contact_card.received webhook events.
A contact belongs to a line, not to an individual chat. You receive one event per person who
shares their contact, regardless of how many chats they have in common with your line.
The event fires again whenever the shared contact’s name or media changes.
Payload for contact_card.received webhook events.
A contact belongs to a line, not to an individual chat. You receive one event per person who shares their contact, regardless of how many chats they have in common with your line.
The event fires again whenever the shared contact’s name or media changes.
URL of the contact’s media, served from cdn.linqapp.com. null when the
contact shared no media, and also when media was shared but could not be
retrieved — this field does not distinguish the two.
Download the media and store it yourself. The URL may be signed and expire, in as little as 45 minutes, and altering its query string invalidates it immediately.
PhoneNumberStatusUpdatedWebhookEvent object { api_version, created_at, data, 5 more } Complete webhook payload for phone_number.status_updated events
Complete webhook payload for phone_number.status_updated events
data: object { changed_at, new_reputation, new_status, 3 more } Payload for phone_number.status_updated webhook events
Payload for phone_number.status_updated webhook events
ConnectionCreatedWebhookEvent object { api_version, created_at, data, 5 more }
data: object { id, amount, checkout_url, 17 more } The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
What was charged at checkout, in the currency’s minor
units. In subscription mode this is the first invoice’s
total — all items after any discounts are applied.
URL the recipient opens to pay
(https://zero.linqapp.com/pay/{slug}?session=...).
discount: optional object { coupon, label, promotion_code } Subscription mode — the discount Stripe applied, read back
from the coupon. Absent when none was applied.
Subscription mode — the discount Stripe applied, read back from the coupon. Absent when none was applied.
interval: optional "day" or "week" or "month" or "year"Subscription mode — how often the subscription renews.
Subscription mode — how often the subscription renews.
mode: optional "payment" or "subscription"Whether the request collected a one-time charge or started a subscription.
Whether the request collected a one-time charge or started a subscription.
natural: optional object { payment_request_id, transaction_id } Natural-rail join keys, present when rail: natural.
Natural-rail join keys, present when rail: natural.
stripe: optional object { customer_id, payment_intent_id, subscription_id } Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
ConnectionRevokedWebhookEvent object { api_version, created_at, data, 5 more }
data: object { id, amount, checkout_url, 17 more } The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
What was charged at checkout, in the currency’s minor
units. In subscription mode this is the first invoice’s
total — all items after any discounts are applied.
URL the recipient opens to pay
(https://zero.linqapp.com/pay/{slug}?session=...).
discount: optional object { coupon, label, promotion_code } Subscription mode — the discount Stripe applied, read back
from the coupon. Absent when none was applied.
Subscription mode — the discount Stripe applied, read back from the coupon. Absent when none was applied.
interval: optional "day" or "week" or "month" or "year"Subscription mode — how often the subscription renews.
Subscription mode — how often the subscription renews.
mode: optional "payment" or "subscription"Whether the request collected a one-time charge or started a subscription.
Whether the request collected a one-time charge or started a subscription.
natural: optional object { payment_request_id, transaction_id } Natural-rail join keys, present when rail: natural.
Natural-rail join keys, present when rail: natural.
stripe: optional object { customer_id, payment_intent_id, subscription_id } Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
LocationSharingStartedWebhookEvent object { api_version, created_at, data, 5 more }
data: object { began_at, chat_id, ends_at, 2 more }
When location sharing started. Always present: falls back to when the share was first observed if the device reported no start time.
The chat this share was first sent to. Location sharing is per-contact rather than per-chat, so the location may also be visible in other chats with the same handle; this identifies where the share originated and does not change if the contact later shares into another chat. Null when the originating chat could not be determined.
LocationSharingStoppedWebhookEvent object { api_version, created_at, data, 5 more }
data: object { began_at, chat_id, ended_at, 2 more }
When the sharing session started, matching began_at on its started event. Always present.
The chat the ended share was first sent to, matching the chat_id on its started event. Sharing always stops for the contact as a whole, never for a single chat, so this is the session’s origin rather than the chat it stopped in. Null when the originating chat could not be determined.
PaymentAuthorizedWebhookEvent object { api_version, created_at, data, 5 more }
data: object { id, amount, checkout_url, 17 more } The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
What was charged at checkout, in the currency’s minor
units. In subscription mode this is the first invoice’s
total — all items after any discounts are applied.
URL the recipient opens to pay
(https://zero.linqapp.com/pay/{slug}?session=...).
discount: optional object { coupon, label, promotion_code } Subscription mode — the discount Stripe applied, read back
from the coupon. Absent when none was applied.
Subscription mode — the discount Stripe applied, read back from the coupon. Absent when none was applied.
interval: optional "day" or "week" or "month" or "year"Subscription mode — how often the subscription renews.
Subscription mode — how often the subscription renews.
mode: optional "payment" or "subscription"Whether the request collected a one-time charge or started a subscription.
Whether the request collected a one-time charge or started a subscription.
natural: optional object { payment_request_id, transaction_id } Natural-rail join keys, present when rail: natural.
Natural-rail join keys, present when rail: natural.
stripe: optional object { customer_id, payment_intent_id, subscription_id } Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
PaymentCanceledWebhookEvent object { api_version, created_at, data, 5 more }
data: object { id, amount, checkout_url, 17 more } The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
What was charged at checkout, in the currency’s minor
units. In subscription mode this is the first invoice’s
total — all items after any discounts are applied.
URL the recipient opens to pay
(https://zero.linqapp.com/pay/{slug}?session=...).
discount: optional object { coupon, label, promotion_code } Subscription mode — the discount Stripe applied, read back
from the coupon. Absent when none was applied.
Subscription mode — the discount Stripe applied, read back from the coupon. Absent when none was applied.
interval: optional "day" or "week" or "month" or "year"Subscription mode — how often the subscription renews.
Subscription mode — how often the subscription renews.
mode: optional "payment" or "subscription"Whether the request collected a one-time charge or started a subscription.
Whether the request collected a one-time charge or started a subscription.
natural: optional object { payment_request_id, transaction_id } Natural-rail join keys, present when rail: natural.
Natural-rail join keys, present when rail: natural.
stripe: optional object { customer_id, payment_intent_id, subscription_id } Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
PaymentDeclinedWebhookEvent object { api_version, created_at, data, 5 more }
data: object { id, amount, checkout_url, 17 more } The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
What was charged at checkout, in the currency’s minor
units. In subscription mode this is the first invoice’s
total — all items after any discounts are applied.
URL the recipient opens to pay
(https://zero.linqapp.com/pay/{slug}?session=...).
discount: optional object { coupon, label, promotion_code } Subscription mode — the discount Stripe applied, read back
from the coupon. Absent when none was applied.
Subscription mode — the discount Stripe applied, read back from the coupon. Absent when none was applied.
interval: optional "day" or "week" or "month" or "year"Subscription mode — how often the subscription renews.
Subscription mode — how often the subscription renews.
mode: optional "payment" or "subscription"Whether the request collected a one-time charge or started a subscription.
Whether the request collected a one-time charge or started a subscription.
natural: optional object { payment_request_id, transaction_id } Natural-rail join keys, present when rail: natural.
Natural-rail join keys, present when rail: natural.
stripe: optional object { customer_id, payment_intent_id, subscription_id } Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
PaymentExpiredWebhookEvent object { api_version, created_at, data, 5 more }
data: object { id, amount, checkout_url, 17 more } The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
What was charged at checkout, in the currency’s minor
units. In subscription mode this is the first invoice’s
total — all items after any discounts are applied.
URL the recipient opens to pay
(https://zero.linqapp.com/pay/{slug}?session=...).
discount: optional object { coupon, label, promotion_code } Subscription mode — the discount Stripe applied, read back
from the coupon. Absent when none was applied.
Subscription mode — the discount Stripe applied, read back from the coupon. Absent when none was applied.
interval: optional "day" or "week" or "month" or "year"Subscription mode — how often the subscription renews.
Subscription mode — how often the subscription renews.
mode: optional "payment" or "subscription"Whether the request collected a one-time charge or started a subscription.
Whether the request collected a one-time charge or started a subscription.
natural: optional object { payment_request_id, transaction_id } Natural-rail join keys, present when rail: natural.
Natural-rail join keys, present when rail: natural.
stripe: optional object { customer_id, payment_intent_id, subscription_id } Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
PaymentSucceededWebhookEvent object { api_version, created_at, data, 5 more }
data: object { id, amount, checkout_url, 17 more } The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
The payment request, as returned by
GET /v3/payment_requests/{paymentRequestId}.
What was charged at checkout, in the currency’s minor
units. In subscription mode this is the first invoice’s
total — all items after any discounts are applied.
URL the recipient opens to pay
(https://zero.linqapp.com/pay/{slug}?session=...).
discount: optional object { coupon, label, promotion_code } Subscription mode — the discount Stripe applied, read back
from the coupon. Absent when none was applied.
Subscription mode — the discount Stripe applied, read back from the coupon. Absent when none was applied.
interval: optional "day" or "week" or "month" or "year"Subscription mode — how often the subscription renews.
Subscription mode — how often the subscription renews.
mode: optional "payment" or "subscription"Whether the request collected a one-time charge or started a subscription.
Whether the request collected a one-time charge or started a subscription.
natural: optional object { payment_request_id, transaction_id } Natural-rail join keys, present when rail: natural.
Natural-rail join keys, present when rail: natural.
stripe: optional object { customer_id, payment_intent_id, subscription_id } Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.
Ids of the Stripe objects on your connected account — join
keys into your own Stripe Dashboard/API. Manage a
subscription’s post-checkout lifecycle with subscription_id.