# Webhooks

## Domain Types

### Message Event V2

- `class MessageEventV2: …`

  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

  - `id: str`

    Message identifier

  - `chat: Chat`

    Chat information

    - `id: str`

      Chat identifier

    - `health_status: ChatHealthStatus`

      **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

      - `doc_url: str`

        Deep-link to the relevant section of the Chat Health guide for this status.

      - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

        Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

        - `"HEALTHY"`

        - `"AT_RISK"`

        - `"CRITICAL"`

        - `"OPTED_OUT"`

      - `updated_at: datetime`

        When this status last changed.

    - `is_group: Optional[bool]`

      Whether this is a group chat

    - `owner_handle: Optional[ChatHandle]`

      Your phone number's handle. Always has is_me=true.

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

  - `direction: Literal["inbound", "outbound"]`

    Message direction - "outbound" if sent by you, "inbound" if received

    - `"inbound"`

    - `"outbound"`

  - `parts: List[Part]`

    Message parts (text and/or media)

    - `class SchemasTextPartResponse: …`

      A text message part

      - `type: Literal["text"]`

        Indicates this is a text message part

        - `"text"`

      - `value: str`

        The text content

      - `mention: Optional[str]`

        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.

      - `mention_range: Optional[List[int]]`

        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[List[Mention]]`

        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.

        - `handle: str`

          Address of the mentioned participant, exactly as the device recorded it — an E.164
          phone number or an email address.

        - `is_me: bool`

          Whether the mentioned participant is this line.

        - `range: List[int]`

          Character range `[start, end)` in `value` highlighted as this mention.
          *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

      - `text_decorations: Optional[List[TextDecoration]]`

        Text decorations applied to character ranges in the value

        - `range: List[int]`

          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.*

        - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

          Animated text effect to apply. Mutually exclusive with `style`.

          - `"big"`

          - `"small"`

          - `"shake"`

          - `"nod"`

          - `"explode"`

          - `"ripple"`

          - `"bloom"`

          - `"jitter"`

        - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

          Text style to apply. Mutually exclusive with `animation`.

          - `"bold"`

          - `"italic"`

          - `"strikethrough"`

          - `"underline"`

    - `class SchemasMediaPartResponse: …`

      A media attachment part

      - `id: str`

        Unique attachment identifier

      - `filename: str`

        Original filename

      - `mime_type: str`

        MIME type of the file

      - `size_bytes: int`

        File size in bytes

      - `type: Literal["media"]`

        Indicates this is a media attachment part

        - `"media"`

      - `url: str`

        Presigned URL for downloading the attachment (expires in 1 hour).

    - `class PartSchemasLinkPartResponse: …`

      A rich link preview part

      - `type: Literal["link"]`

        Indicates this is a rich link preview part

        - `"link"`

      - `value: str`

        The URL

    - `class PartSchemasIMessageAppPartResponse: …`

      An iMessage app card part.

      - `app: PartSchemasIMessageAppPartResponseApp`

        Identifies the iMessage app (Messages app extension) that backs the card.

        - `bundle_id: str`

          Bundle identifier of the Messages app extension.

        - `name: str`

          Display name of the app.

        - `team_id: str`

          The app's 10-character team identifier.

        - `app_store_id: Optional[int]`

          The owning app's App Store id, when known.

      - `layout: PartSchemasIMessageAppPartResponseLayout`

        Visible layout of the card.

        - `caption: Optional[str]`

          Primary label, top-left and bold.

        - `subcaption: Optional[str]`

          Secondary label, below caption on the left.

        - `trailing_caption: Optional[str]`

          Label shown top-right.

        - `trailing_subcaption: Optional[str]`

          Label shown below trailing_caption.

      - `type: Literal["imessage_app"]`

        Indicates this is an iMessage app card part.

        - `"imessage_app"`

      - `url: str`

        The URL the recipient's app opens when the user taps the card.

      - `fallback_text: Optional[str]`

        Fallback text for surfaces that cannot render the card.

    - `class PartSchemasAppClipPartResponse: …`

      An Apple Pay App Clip payment card part

      - `type: Literal["app_clip"]`

        Indicates this is an App Clip payment card part

        - `"app_clip"`

      - `value: str`

        The checkout link the card opens

      - `description: Optional[str]`

        The card's summary line, composed by Linq from the checkout session

      - `image_url: Optional[str]`

        The card's preview image

      - `title: Optional[str]`

        The card's headline, composed by Linq from the checkout session

  - `sender_handle: ChatHandle`

    The handle that sent this message

  - `service: ServiceType`

    Messaging service type

  - `delivered_at: Optional[datetime]`

    When the message was delivered. Null if not yet delivered.

  - `effect: Optional[SchemasMessageEffect]`

    iMessage effect applied to a message (screen or bubble animation)

    - `name: Optional[str]`

      Effect name (confetti, fireworks, slam, gentle, etc.)

    - `type: Optional[Literal["screen", "bubble"]]`

      Effect category

      - `"screen"`

      - `"bubble"`

  - `idempotency_key: Optional[str]`

    Idempotency key for deduplication of outbound messages.

  - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

    Preferred messaging service type. Includes "auto" for default fallback behavior.

    - `"iMessage"`

    - `"SMS"`

    - `"RCS"`

    - `"auto"`

  - `read_at: Optional[datetime]`

    When the message was read. Null if not yet read.

  - `reconciled_at: Optional[datetime]`

    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).

  - `reply_to: Optional[ReplyTo]`

    Reference to the message this is replying to (for threaded replies)

    - `message_id: Optional[str]`

      ID of the message being replied to

    - `part_index: Optional[int]`

      Index of the part being replied to

  - `sent_at: Optional[datetime]`

    When the message was sent. Null if not yet sent.

  - `zero_retention: Optional[bool]`

    True when this message was sent on a zero-day-retention line. `parts` is always empty in that case — Linq never persists this message's content, so there is nothing to include here, not even a count or type of what was sent.

### Message Payload

- `class MessagePayload: …`

  Message content nested within webhook events

  - `id: Optional[str]`

    Message identifier

  - `created_at: Optional[datetime]`

    When the message record was created

  - `delivered_at: Optional[datetime]`

    When the message was delivered

  - `effect: Optional[SchemasMessageEffect]`

    iMessage effect applied to a message (screen or bubble animation)

    - `name: Optional[str]`

      Effect name (confetti, fireworks, slam, gentle, etc.)

    - `type: Optional[Literal["screen", "bubble"]]`

      Effect category

      - `"screen"`

      - `"bubble"`

  - `is_delivered: Optional[bool]`

    Whether the message has been delivered

  - `is_read: Optional[bool]`

    Whether the message has been read

  - `parts: Optional[List[Part]]`

    Message content parts (text and/or media)

    - `class SchemasTextPartResponse: …`

      A text message part

      - `type: Literal["text"]`

        Indicates this is a text message part

        - `"text"`

      - `value: str`

        The text content

      - `mention: Optional[str]`

        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.

      - `mention_range: Optional[List[int]]`

        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[List[Mention]]`

        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.

        - `handle: str`

          Address of the mentioned participant, exactly as the device recorded it — an E.164
          phone number or an email address.

        - `is_me: bool`

          Whether the mentioned participant is this line.

        - `range: List[int]`

          Character range `[start, end)` in `value` highlighted as this mention.
          *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

      - `text_decorations: Optional[List[TextDecoration]]`

        Text decorations applied to character ranges in the value

        - `range: List[int]`

          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.*

        - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

          Animated text effect to apply. Mutually exclusive with `style`.

          - `"big"`

          - `"small"`

          - `"shake"`

          - `"nod"`

          - `"explode"`

          - `"ripple"`

          - `"bloom"`

          - `"jitter"`

        - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

          Text style to apply. Mutually exclusive with `animation`.

          - `"bold"`

          - `"italic"`

          - `"strikethrough"`

          - `"underline"`

    - `class SchemasMediaPartResponse: …`

      A media attachment part

      - `id: str`

        Unique attachment identifier

      - `filename: str`

        Original filename

      - `mime_type: str`

        MIME type of the file

      - `size_bytes: int`

        File size in bytes

      - `type: Literal["media"]`

        Indicates this is a media attachment part

        - `"media"`

      - `url: str`

        Presigned URL for downloading the attachment (expires in 1 hour).

    - `class PartSchemasLinkPartResponse: …`

      A rich link preview part

      - `type: Literal["link"]`

        Indicates this is a rich link preview part

        - `"link"`

      - `value: str`

        The URL

    - `class PartSchemasIMessageAppPartResponse: …`

      An iMessage app card part.

      - `app: PartSchemasIMessageAppPartResponseApp`

        Identifies the iMessage app (Messages app extension) that backs the card.

        - `bundle_id: str`

          Bundle identifier of the Messages app extension.

        - `name: str`

          Display name of the app.

        - `team_id: str`

          The app's 10-character team identifier.

        - `app_store_id: Optional[int]`

          The owning app's App Store id, when known.

      - `layout: PartSchemasIMessageAppPartResponseLayout`

        Visible layout of the card.

        - `caption: Optional[str]`

          Primary label, top-left and bold.

        - `subcaption: Optional[str]`

          Secondary label, below caption on the left.

        - `trailing_caption: Optional[str]`

          Label shown top-right.

        - `trailing_subcaption: Optional[str]`

          Label shown below trailing_caption.

      - `type: Literal["imessage_app"]`

        Indicates this is an iMessage app card part.

        - `"imessage_app"`

      - `url: str`

        The URL the recipient's app opens when the user taps the card.

      - `fallback_text: Optional[str]`

        Fallback text for surfaces that cannot render the card.

    - `class PartSchemasAppClipPartResponse: …`

      An Apple Pay App Clip payment card part

      - `type: Literal["app_clip"]`

        Indicates this is an App Clip payment card part

        - `"app_clip"`

      - `value: str`

        The checkout link the card opens

      - `description: Optional[str]`

        The card's summary line, composed by Linq from the checkout session

      - `image_url: Optional[str]`

        The card's preview image

      - `title: Optional[str]`

        The card's headline, composed by Linq from the checkout session

  - `read_at: Optional[datetime]`

    When the message was read

  - `reconciled_at: Optional[datetime]`

    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).

  - `reply_to: Optional[ReplyTo]`

    Reference to the message this is replying to

    - `message_id: Optional[str]`

      The ID of the message being replied to

    - `part_index: Optional[int]`

      Index of the message part being replied to (0-based)

  - `sent_at: Optional[datetime]`

    When the message was sent

  - `updated_at: Optional[datetime]`

    When the message record was last updated

  - `zero_retention: Optional[bool]`

    True when this message was sent on a zero-day-retention line. `parts` is always empty in that case — Linq never persists this message's content, so there is nothing to include here, not even a count or type of what was sent.

### Reaction Event Base

- `class ReactionEventBase: …`

  - `is_from_me: bool`

    Whether this reaction was from the owner of the phone number (true) or from someone else (false)

  - `reaction_type: ReactionType`

    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.

    - `"love"`

    - `"like"`

    - `"dislike"`

    - `"laugh"`

    - `"emphasize"`

    - `"question"`

    - `"custom"`

    - `"sticker"`

  - `chat_id: Optional[str]`

    Chat identifier (UUID)

  - `custom_emoji: Optional[str]`

    The actual emoji when reaction_type is "custom". Null for standard tapbacks.

  - `from_: Optional[str]`

    DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.

  - `from_handle: Optional[ChatHandle]`

    The person who added/removed the reaction as a full handle object

    - `id: str`

      Unique identifier for this handle

    - `handle: str`

      Phone number (E.164) or email address of the participant

    - `joined_at: datetime`

      When this participant joined the chat

    - `service: ServiceType`

      Messaging service type

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

    - `is_me: Optional[bool]`

      Whether this handle belongs to the sender (your phone number)

    - `left_at: Optional[datetime]`

      When they left (if applicable)

    - `status: Optional[Literal["active", "left", "removed"]]`

      Participant status

      - `"active"`

      - `"left"`

      - `"removed"`

  - `message_id: Optional[str]`

    Message identifier (UUID) that the reaction was added to or removed from

  - `part_index: Optional[int]`

    Index of the message part that was reacted to (0-based)

  - `reacted_at: Optional[datetime]`

    When the reaction was added or removed

  - `reaction_id: Optional[str]`

    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.

  - `service: Optional[ServiceType]`

    Messaging service type

  - `sticker: Optional[Sticker]`

    Sticker attachment details when reaction_type is "sticker". Null for non-sticker reactions.

    - `file_name: Optional[str]`

      Filename of the sticker

    - `height: Optional[int]`

      Sticker image height in pixels

    - `mime_type: Optional[str]`

      MIME type of the sticker image

    - `url: Optional[str]`

      Presigned URL for downloading the sticker image (expires in 1 hour).

    - `width: Optional[int]`

      Sticker image width in pixels

### Schemas Media Part Response

- `class SchemasMediaPartResponse: …`

  A media attachment part

  - `id: str`

    Unique attachment identifier

  - `filename: str`

    Original filename

  - `mime_type: str`

    MIME type of the file

  - `size_bytes: int`

    File size in bytes

  - `type: Literal["media"]`

    Indicates this is a media attachment part

    - `"media"`

  - `url: str`

    Presigned URL for downloading the attachment (expires in 1 hour).

### Schemas Message Effect

- `class SchemasMessageEffect: …`

  iMessage effect applied to a message (screen or bubble animation)

  - `name: Optional[str]`

    Effect name (confetti, fireworks, slam, gentle, etc.)

  - `type: Optional[Literal["screen", "bubble"]]`

    Effect category

    - `"screen"`

    - `"bubble"`

### Schemas Text Part Response

- `class SchemasTextPartResponse: …`

  A text message part

  - `type: Literal["text"]`

    Indicates this is a text message part

    - `"text"`

  - `value: str`

    The text content

  - `mention: Optional[str]`

    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.

  - `mention_range: Optional[List[int]]`

    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[List[Mention]]`

    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.

    - `handle: str`

      Address of the mentioned participant, exactly as the device recorded it — an E.164
      phone number or an email address.

    - `is_me: bool`

      Whether the mentioned participant is this line.

    - `range: List[int]`

      Character range `[start, end)` in `value` highlighted as this mention.
      *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

  - `text_decorations: Optional[List[TextDecoration]]`

    Text decorations applied to character ranges in the value

    - `range: List[int]`

      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.*

    - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

      Animated text effect to apply. Mutually exclusive with `style`.

      - `"big"`

      - `"small"`

      - `"shake"`

      - `"nod"`

      - `"explode"`

      - `"ripple"`

      - `"bloom"`

      - `"jitter"`

    - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

      Text style to apply. Mutually exclusive with `animation`.

      - `"bold"`

      - `"italic"`

      - `"strikethrough"`

      - `"underline"`

### message.sent

- `class MessageSentWebhookEvent: …`

  Complete webhook payload for message.sent events (2026-02-03 format)

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: MessageEventV2`

    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

    - `id: str`

      Message identifier

    - `chat: Chat`

      Chat information

      - `id: str`

        Chat identifier

      - `health_status: ChatHealthStatus`

        **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

        - `doc_url: str`

          Deep-link to the relevant section of the Chat Health guide for this status.

        - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

          Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

          - `"HEALTHY"`

          - `"AT_RISK"`

          - `"CRITICAL"`

          - `"OPTED_OUT"`

        - `updated_at: datetime`

          When this status last changed.

      - `is_group: Optional[bool]`

        Whether this is a group chat

      - `owner_handle: Optional[ChatHandle]`

        Your phone number's handle. Always has is_me=true.

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["inbound", "outbound"]`

      Message direction - "outbound" if sent by you, "inbound" if received

      - `"inbound"`

      - `"outbound"`

    - `parts: List[Part]`

      Message parts (text and/or media)

      - `class SchemasTextPartResponse: …`

        A text message part

        - `type: Literal["text"]`

          Indicates this is a text message part

          - `"text"`

        - `value: str`

          The text content

        - `mention: Optional[str]`

          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.

        - `mention_range: Optional[List[int]]`

          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[List[Mention]]`

          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.

          - `handle: str`

            Address of the mentioned participant, exactly as the device recorded it — an E.164
            phone number or an email address.

          - `is_me: bool`

            Whether the mentioned participant is this line.

          - `range: List[int]`

            Character range `[start, end)` in `value` highlighted as this mention.
            *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

        - `text_decorations: Optional[List[TextDecoration]]`

          Text decorations applied to character ranges in the value

          - `range: List[int]`

            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.*

          - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

            Animated text effect to apply. Mutually exclusive with `style`.

            - `"big"`

            - `"small"`

            - `"shake"`

            - `"nod"`

            - `"explode"`

            - `"ripple"`

            - `"bloom"`

            - `"jitter"`

          - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

            Text style to apply. Mutually exclusive with `animation`.

            - `"bold"`

            - `"italic"`

            - `"strikethrough"`

            - `"underline"`

      - `class SchemasMediaPartResponse: …`

        A media attachment part

        - `id: str`

          Unique attachment identifier

        - `filename: str`

          Original filename

        - `mime_type: str`

          MIME type of the file

        - `size_bytes: int`

          File size in bytes

        - `type: Literal["media"]`

          Indicates this is a media attachment part

          - `"media"`

        - `url: str`

          Presigned URL for downloading the attachment (expires in 1 hour).

      - `class PartSchemasLinkPartResponse: …`

        A rich link preview part

        - `type: Literal["link"]`

          Indicates this is a rich link preview part

          - `"link"`

        - `value: str`

          The URL

      - `class PartSchemasIMessageAppPartResponse: …`

        An iMessage app card part.

        - `app: PartSchemasIMessageAppPartResponseApp`

          Identifies the iMessage app (Messages app extension) that backs the card.

          - `bundle_id: str`

            Bundle identifier of the Messages app extension.

          - `name: str`

            Display name of the app.

          - `team_id: str`

            The app's 10-character team identifier.

          - `app_store_id: Optional[int]`

            The owning app's App Store id, when known.

        - `layout: PartSchemasIMessageAppPartResponseLayout`

          Visible layout of the card.

          - `caption: Optional[str]`

            Primary label, top-left and bold.

          - `subcaption: Optional[str]`

            Secondary label, below caption on the left.

          - `trailing_caption: Optional[str]`

            Label shown top-right.

          - `trailing_subcaption: Optional[str]`

            Label shown below trailing_caption.

        - `type: Literal["imessage_app"]`

          Indicates this is an iMessage app card part.

          - `"imessage_app"`

        - `url: str`

          The URL the recipient's app opens when the user taps the card.

        - `fallback_text: Optional[str]`

          Fallback text for surfaces that cannot render the card.

      - `class PartSchemasAppClipPartResponse: …`

        An Apple Pay App Clip payment card part

        - `type: Literal["app_clip"]`

          Indicates this is an App Clip payment card part

          - `"app_clip"`

        - `value: str`

          The checkout link the card opens

        - `description: Optional[str]`

          The card's summary line, composed by Linq from the checkout session

        - `image_url: Optional[str]`

          The card's preview image

        - `title: Optional[str]`

          The card's headline, composed by Linq from the checkout session

    - `sender_handle: ChatHandle`

      The handle that sent this message

    - `service: ServiceType`

      Messaging service type

    - `delivered_at: Optional[datetime]`

      When the message was delivered. Null if not yet delivered.

    - `effect: Optional[SchemasMessageEffect]`

      iMessage effect applied to a message (screen or bubble animation)

      - `name: Optional[str]`

        Effect name (confetti, fireworks, slam, gentle, etc.)

      - `type: Optional[Literal["screen", "bubble"]]`

        Effect category

        - `"screen"`

        - `"bubble"`

    - `idempotency_key: Optional[str]`

      Idempotency key for deduplication of outbound messages.

    - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

      Preferred messaging service type. Includes "auto" for default fallback behavior.

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

      - `"auto"`

    - `read_at: Optional[datetime]`

      When the message was read. Null if not yet read.

    - `reconciled_at: Optional[datetime]`

      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).

    - `reply_to: Optional[ReplyTo]`

      Reference to the message this is replying to (for threaded replies)

      - `message_id: Optional[str]`

        ID of the message being replied to

      - `part_index: Optional[int]`

        Index of the part being replied to

    - `sent_at: Optional[datetime]`

      When the message was sent. Null if not yet sent.

    - `zero_retention: Optional[bool]`

      True when this message was sent on a zero-day-retention line. `parts` is always empty in that case — Linq never persists this message's content, so there is nothing to include here, not even a count or type of what was sent.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### message.received

- `class MessageReceivedWebhookEvent: …`

  Complete webhook payload for message.received events (2026-02-03 format)

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: MessageEventV2`

    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

    - `id: str`

      Message identifier

    - `chat: Chat`

      Chat information

      - `id: str`

        Chat identifier

      - `health_status: ChatHealthStatus`

        **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

        - `doc_url: str`

          Deep-link to the relevant section of the Chat Health guide for this status.

        - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

          Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

          - `"HEALTHY"`

          - `"AT_RISK"`

          - `"CRITICAL"`

          - `"OPTED_OUT"`

        - `updated_at: datetime`

          When this status last changed.

      - `is_group: Optional[bool]`

        Whether this is a group chat

      - `owner_handle: Optional[ChatHandle]`

        Your phone number's handle. Always has is_me=true.

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["inbound", "outbound"]`

      Message direction - "outbound" if sent by you, "inbound" if received

      - `"inbound"`

      - `"outbound"`

    - `parts: List[Part]`

      Message parts (text and/or media)

      - `class SchemasTextPartResponse: …`

        A text message part

        - `type: Literal["text"]`

          Indicates this is a text message part

          - `"text"`

        - `value: str`

          The text content

        - `mention: Optional[str]`

          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.

        - `mention_range: Optional[List[int]]`

          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[List[Mention]]`

          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.

          - `handle: str`

            Address of the mentioned participant, exactly as the device recorded it — an E.164
            phone number or an email address.

          - `is_me: bool`

            Whether the mentioned participant is this line.

          - `range: List[int]`

            Character range `[start, end)` in `value` highlighted as this mention.
            *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

        - `text_decorations: Optional[List[TextDecoration]]`

          Text decorations applied to character ranges in the value

          - `range: List[int]`

            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.*

          - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

            Animated text effect to apply. Mutually exclusive with `style`.

            - `"big"`

            - `"small"`

            - `"shake"`

            - `"nod"`

            - `"explode"`

            - `"ripple"`

            - `"bloom"`

            - `"jitter"`

          - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

            Text style to apply. Mutually exclusive with `animation`.

            - `"bold"`

            - `"italic"`

            - `"strikethrough"`

            - `"underline"`

      - `class SchemasMediaPartResponse: …`

        A media attachment part

        - `id: str`

          Unique attachment identifier

        - `filename: str`

          Original filename

        - `mime_type: str`

          MIME type of the file

        - `size_bytes: int`

          File size in bytes

        - `type: Literal["media"]`

          Indicates this is a media attachment part

          - `"media"`

        - `url: str`

          Presigned URL for downloading the attachment (expires in 1 hour).

      - `class PartSchemasLinkPartResponse: …`

        A rich link preview part

        - `type: Literal["link"]`

          Indicates this is a rich link preview part

          - `"link"`

        - `value: str`

          The URL

      - `class PartSchemasIMessageAppPartResponse: …`

        An iMessage app card part.

        - `app: PartSchemasIMessageAppPartResponseApp`

          Identifies the iMessage app (Messages app extension) that backs the card.

          - `bundle_id: str`

            Bundle identifier of the Messages app extension.

          - `name: str`

            Display name of the app.

          - `team_id: str`

            The app's 10-character team identifier.

          - `app_store_id: Optional[int]`

            The owning app's App Store id, when known.

        - `layout: PartSchemasIMessageAppPartResponseLayout`

          Visible layout of the card.

          - `caption: Optional[str]`

            Primary label, top-left and bold.

          - `subcaption: Optional[str]`

            Secondary label, below caption on the left.

          - `trailing_caption: Optional[str]`

            Label shown top-right.

          - `trailing_subcaption: Optional[str]`

            Label shown below trailing_caption.

        - `type: Literal["imessage_app"]`

          Indicates this is an iMessage app card part.

          - `"imessage_app"`

        - `url: str`

          The URL the recipient's app opens when the user taps the card.

        - `fallback_text: Optional[str]`

          Fallback text for surfaces that cannot render the card.

      - `class PartSchemasAppClipPartResponse: …`

        An Apple Pay App Clip payment card part

        - `type: Literal["app_clip"]`

          Indicates this is an App Clip payment card part

          - `"app_clip"`

        - `value: str`

          The checkout link the card opens

        - `description: Optional[str]`

          The card's summary line, composed by Linq from the checkout session

        - `image_url: Optional[str]`

          The card's preview image

        - `title: Optional[str]`

          The card's headline, composed by Linq from the checkout session

    - `sender_handle: ChatHandle`

      The handle that sent this message

    - `service: ServiceType`

      Messaging service type

    - `delivered_at: Optional[datetime]`

      When the message was delivered. Null if not yet delivered.

    - `effect: Optional[SchemasMessageEffect]`

      iMessage effect applied to a message (screen or bubble animation)

      - `name: Optional[str]`

        Effect name (confetti, fireworks, slam, gentle, etc.)

      - `type: Optional[Literal["screen", "bubble"]]`

        Effect category

        - `"screen"`

        - `"bubble"`

    - `idempotency_key: Optional[str]`

      Idempotency key for deduplication of outbound messages.

    - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

      Preferred messaging service type. Includes "auto" for default fallback behavior.

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

      - `"auto"`

    - `read_at: Optional[datetime]`

      When the message was read. Null if not yet read.

    - `reconciled_at: Optional[datetime]`

      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).

    - `reply_to: Optional[ReplyTo]`

      Reference to the message this is replying to (for threaded replies)

      - `message_id: Optional[str]`

        ID of the message being replied to

      - `part_index: Optional[int]`

        Index of the part being replied to

    - `sent_at: Optional[datetime]`

      When the message was sent. Null if not yet sent.

    - `zero_retention: Optional[bool]`

      True when this message was sent on a zero-day-retention line. `parts` is always empty in that case — Linq never persists this message's content, so there is nothing to include here, not even a count or type of what was sent.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### message.read

- `class MessageReadWebhookEvent: …`

  Complete webhook payload for message.read events (2026-02-03 format)

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: MessageEventV2`

    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

    - `id: str`

      Message identifier

    - `chat: Chat`

      Chat information

      - `id: str`

        Chat identifier

      - `health_status: ChatHealthStatus`

        **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

        - `doc_url: str`

          Deep-link to the relevant section of the Chat Health guide for this status.

        - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

          Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

          - `"HEALTHY"`

          - `"AT_RISK"`

          - `"CRITICAL"`

          - `"OPTED_OUT"`

        - `updated_at: datetime`

          When this status last changed.

      - `is_group: Optional[bool]`

        Whether this is a group chat

      - `owner_handle: Optional[ChatHandle]`

        Your phone number's handle. Always has is_me=true.

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["inbound", "outbound"]`

      Message direction - "outbound" if sent by you, "inbound" if received

      - `"inbound"`

      - `"outbound"`

    - `parts: List[Part]`

      Message parts (text and/or media)

      - `class SchemasTextPartResponse: …`

        A text message part

        - `type: Literal["text"]`

          Indicates this is a text message part

          - `"text"`

        - `value: str`

          The text content

        - `mention: Optional[str]`

          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.

        - `mention_range: Optional[List[int]]`

          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[List[Mention]]`

          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.

          - `handle: str`

            Address of the mentioned participant, exactly as the device recorded it — an E.164
            phone number or an email address.

          - `is_me: bool`

            Whether the mentioned participant is this line.

          - `range: List[int]`

            Character range `[start, end)` in `value` highlighted as this mention.
            *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

        - `text_decorations: Optional[List[TextDecoration]]`

          Text decorations applied to character ranges in the value

          - `range: List[int]`

            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.*

          - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

            Animated text effect to apply. Mutually exclusive with `style`.

            - `"big"`

            - `"small"`

            - `"shake"`

            - `"nod"`

            - `"explode"`

            - `"ripple"`

            - `"bloom"`

            - `"jitter"`

          - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

            Text style to apply. Mutually exclusive with `animation`.

            - `"bold"`

            - `"italic"`

            - `"strikethrough"`

            - `"underline"`

      - `class SchemasMediaPartResponse: …`

        A media attachment part

        - `id: str`

          Unique attachment identifier

        - `filename: str`

          Original filename

        - `mime_type: str`

          MIME type of the file

        - `size_bytes: int`

          File size in bytes

        - `type: Literal["media"]`

          Indicates this is a media attachment part

          - `"media"`

        - `url: str`

          Presigned URL for downloading the attachment (expires in 1 hour).

      - `class PartSchemasLinkPartResponse: …`

        A rich link preview part

        - `type: Literal["link"]`

          Indicates this is a rich link preview part

          - `"link"`

        - `value: str`

          The URL

      - `class PartSchemasIMessageAppPartResponse: …`

        An iMessage app card part.

        - `app: PartSchemasIMessageAppPartResponseApp`

          Identifies the iMessage app (Messages app extension) that backs the card.

          - `bundle_id: str`

            Bundle identifier of the Messages app extension.

          - `name: str`

            Display name of the app.

          - `team_id: str`

            The app's 10-character team identifier.

          - `app_store_id: Optional[int]`

            The owning app's App Store id, when known.

        - `layout: PartSchemasIMessageAppPartResponseLayout`

          Visible layout of the card.

          - `caption: Optional[str]`

            Primary label, top-left and bold.

          - `subcaption: Optional[str]`

            Secondary label, below caption on the left.

          - `trailing_caption: Optional[str]`

            Label shown top-right.

          - `trailing_subcaption: Optional[str]`

            Label shown below trailing_caption.

        - `type: Literal["imessage_app"]`

          Indicates this is an iMessage app card part.

          - `"imessage_app"`

        - `url: str`

          The URL the recipient's app opens when the user taps the card.

        - `fallback_text: Optional[str]`

          Fallback text for surfaces that cannot render the card.

      - `class PartSchemasAppClipPartResponse: …`

        An Apple Pay App Clip payment card part

        - `type: Literal["app_clip"]`

          Indicates this is an App Clip payment card part

          - `"app_clip"`

        - `value: str`

          The checkout link the card opens

        - `description: Optional[str]`

          The card's summary line, composed by Linq from the checkout session

        - `image_url: Optional[str]`

          The card's preview image

        - `title: Optional[str]`

          The card's headline, composed by Linq from the checkout session

    - `sender_handle: ChatHandle`

      The handle that sent this message

    - `service: ServiceType`

      Messaging service type

    - `delivered_at: Optional[datetime]`

      When the message was delivered. Null if not yet delivered.

    - `effect: Optional[SchemasMessageEffect]`

      iMessage effect applied to a message (screen or bubble animation)

      - `name: Optional[str]`

        Effect name (confetti, fireworks, slam, gentle, etc.)

      - `type: Optional[Literal["screen", "bubble"]]`

        Effect category

        - `"screen"`

        - `"bubble"`

    - `idempotency_key: Optional[str]`

      Idempotency key for deduplication of outbound messages.

    - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

      Preferred messaging service type. Includes "auto" for default fallback behavior.

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

      - `"auto"`

    - `read_at: Optional[datetime]`

      When the message was read. Null if not yet read.

    - `reconciled_at: Optional[datetime]`

      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).

    - `reply_to: Optional[ReplyTo]`

      Reference to the message this is replying to (for threaded replies)

      - `message_id: Optional[str]`

        ID of the message being replied to

      - `part_index: Optional[int]`

        Index of the part being replied to

    - `sent_at: Optional[datetime]`

      When the message was sent. Null if not yet sent.

    - `zero_retention: Optional[bool]`

      True when this message was sent on a zero-day-retention line. `parts` is always empty in that case — Linq never persists this message's content, so there is nothing to include here, not even a count or type of what was sent.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### message.delivered

- `class MessageDeliveredWebhookEvent: …`

  Complete webhook payload for message.delivered events (2026-02-03 format)

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: MessageEventV2`

    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

    - `id: str`

      Message identifier

    - `chat: Chat`

      Chat information

      - `id: str`

        Chat identifier

      - `health_status: ChatHealthStatus`

        **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

        - `doc_url: str`

          Deep-link to the relevant section of the Chat Health guide for this status.

        - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

          Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

          - `"HEALTHY"`

          - `"AT_RISK"`

          - `"CRITICAL"`

          - `"OPTED_OUT"`

        - `updated_at: datetime`

          When this status last changed.

      - `is_group: Optional[bool]`

        Whether this is a group chat

      - `owner_handle: Optional[ChatHandle]`

        Your phone number's handle. Always has is_me=true.

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["inbound", "outbound"]`

      Message direction - "outbound" if sent by you, "inbound" if received

      - `"inbound"`

      - `"outbound"`

    - `parts: List[Part]`

      Message parts (text and/or media)

      - `class SchemasTextPartResponse: …`

        A text message part

        - `type: Literal["text"]`

          Indicates this is a text message part

          - `"text"`

        - `value: str`

          The text content

        - `mention: Optional[str]`

          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.

        - `mention_range: Optional[List[int]]`

          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[List[Mention]]`

          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.

          - `handle: str`

            Address of the mentioned participant, exactly as the device recorded it — an E.164
            phone number or an email address.

          - `is_me: bool`

            Whether the mentioned participant is this line.

          - `range: List[int]`

            Character range `[start, end)` in `value` highlighted as this mention.
            *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

        - `text_decorations: Optional[List[TextDecoration]]`

          Text decorations applied to character ranges in the value

          - `range: List[int]`

            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.*

          - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

            Animated text effect to apply. Mutually exclusive with `style`.

            - `"big"`

            - `"small"`

            - `"shake"`

            - `"nod"`

            - `"explode"`

            - `"ripple"`

            - `"bloom"`

            - `"jitter"`

          - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

            Text style to apply. Mutually exclusive with `animation`.

            - `"bold"`

            - `"italic"`

            - `"strikethrough"`

            - `"underline"`

      - `class SchemasMediaPartResponse: …`

        A media attachment part

        - `id: str`

          Unique attachment identifier

        - `filename: str`

          Original filename

        - `mime_type: str`

          MIME type of the file

        - `size_bytes: int`

          File size in bytes

        - `type: Literal["media"]`

          Indicates this is a media attachment part

          - `"media"`

        - `url: str`

          Presigned URL for downloading the attachment (expires in 1 hour).

      - `class PartSchemasLinkPartResponse: …`

        A rich link preview part

        - `type: Literal["link"]`

          Indicates this is a rich link preview part

          - `"link"`

        - `value: str`

          The URL

      - `class PartSchemasIMessageAppPartResponse: …`

        An iMessage app card part.

        - `app: PartSchemasIMessageAppPartResponseApp`

          Identifies the iMessage app (Messages app extension) that backs the card.

          - `bundle_id: str`

            Bundle identifier of the Messages app extension.

          - `name: str`

            Display name of the app.

          - `team_id: str`

            The app's 10-character team identifier.

          - `app_store_id: Optional[int]`

            The owning app's App Store id, when known.

        - `layout: PartSchemasIMessageAppPartResponseLayout`

          Visible layout of the card.

          - `caption: Optional[str]`

            Primary label, top-left and bold.

          - `subcaption: Optional[str]`

            Secondary label, below caption on the left.

          - `trailing_caption: Optional[str]`

            Label shown top-right.

          - `trailing_subcaption: Optional[str]`

            Label shown below trailing_caption.

        - `type: Literal["imessage_app"]`

          Indicates this is an iMessage app card part.

          - `"imessage_app"`

        - `url: str`

          The URL the recipient's app opens when the user taps the card.

        - `fallback_text: Optional[str]`

          Fallback text for surfaces that cannot render the card.

      - `class PartSchemasAppClipPartResponse: …`

        An Apple Pay App Clip payment card part

        - `type: Literal["app_clip"]`

          Indicates this is an App Clip payment card part

          - `"app_clip"`

        - `value: str`

          The checkout link the card opens

        - `description: Optional[str]`

          The card's summary line, composed by Linq from the checkout session

        - `image_url: Optional[str]`

          The card's preview image

        - `title: Optional[str]`

          The card's headline, composed by Linq from the checkout session

    - `sender_handle: ChatHandle`

      The handle that sent this message

    - `service: ServiceType`

      Messaging service type

    - `delivered_at: Optional[datetime]`

      When the message was delivered. Null if not yet delivered.

    - `effect: Optional[SchemasMessageEffect]`

      iMessage effect applied to a message (screen or bubble animation)

      - `name: Optional[str]`

        Effect name (confetti, fireworks, slam, gentle, etc.)

      - `type: Optional[Literal["screen", "bubble"]]`

        Effect category

        - `"screen"`

        - `"bubble"`

    - `idempotency_key: Optional[str]`

      Idempotency key for deduplication of outbound messages.

    - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

      Preferred messaging service type. Includes "auto" for default fallback behavior.

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

      - `"auto"`

    - `read_at: Optional[datetime]`

      When the message was read. Null if not yet read.

    - `reconciled_at: Optional[datetime]`

      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).

    - `reply_to: Optional[ReplyTo]`

      Reference to the message this is replying to (for threaded replies)

      - `message_id: Optional[str]`

        ID of the message being replied to

      - `part_index: Optional[int]`

        Index of the part being replied to

    - `sent_at: Optional[datetime]`

      When the message was sent. Null if not yet sent.

    - `zero_retention: Optional[bool]`

      True when this message was sent on a zero-day-retention line. `parts` is always empty in that case — Linq never persists this message's content, so there is nothing to include here, not even a count or type of what was sent.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### message.failed

- `class MessageFailedWebhookEvent: …`

  Complete webhook payload for message.failed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Error details for message.failed webhook events.
    See [WebhookErrorCode](#/components/schemas/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.

    - `code: int`

      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.

    - `failed_at: datetime`

      When the failure was detected

    - `chat_id: Optional[str]`

      Chat identifier (UUID)

    - `detail_code: Optional[int]`

      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.

    - `message_id: Optional[str]`

      Message identifier (UUID)

    - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

      Preferred messaging service type. Includes "auto" for default fallback behavior.

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

      - `"auto"`

    - `reason: Optional[str]`

      Human-readable description of the failure

    - `service: Optional[ServiceType]`

      Messaging service type

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### message.edited

- `class MessageEditedWebhookEvent: …`

  Complete webhook payload for message.edited events (2026-02-03 format only)

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    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"`.

    - `id: str`

      Message identifier

    - `chat: DataChat`

      Chat context

      - `id: str`

        Chat identifier

      - `health_status: DataChatHealthStatus`

        **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

        - `doc_url: str`

          Deep-link to the relevant section of the Chat Health guide for this status.

        - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

          Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

          - `"HEALTHY"`

          - `"AT_RISK"`

          - `"CRITICAL"`

          - `"OPTED_OUT"`

        - `updated_at: datetime`

          When this status last changed.

      - `is_group: bool`

        Whether this is a group chat

      - `owner_handle: ChatHandle`

        The handle that owns this chat (your phone number)

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["outbound", "inbound"]`

      "outbound" if you sent the original message, "inbound" if you received it

      - `"outbound"`

      - `"inbound"`

    - `edited_at: datetime`

      When the edit occurred

    - `part: DataPart`

      The edited part

      - `index: int`

        Zero-based index of the edited part within the message

      - `text: str`

        New text content of the part

    - `sender_handle: ChatHandle`

      The handle that sent (and edited) this message

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### reaction.added

- `class ReactionAddedWebhookEvent: …`

  Complete webhook payload for reaction.added events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: ReactionEventBase`

    Payload for reaction.added webhook events

    - `is_from_me: bool`

      Whether this reaction was from the owner of the phone number (true) or from someone else (false)

    - `reaction_type: ReactionType`

      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.

      - `"love"`

      - `"like"`

      - `"dislike"`

      - `"laugh"`

      - `"emphasize"`

      - `"question"`

      - `"custom"`

      - `"sticker"`

    - `chat_id: Optional[str]`

      Chat identifier (UUID)

    - `custom_emoji: Optional[str]`

      The actual emoji when reaction_type is "custom". Null for standard tapbacks.

    - `from_: Optional[str]`

      DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.

    - `from_handle: Optional[ChatHandle]`

      The person who added/removed the reaction as a full handle object

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

    - `message_id: Optional[str]`

      Message identifier (UUID) that the reaction was added to or removed from

    - `part_index: Optional[int]`

      Index of the message part that was reacted to (0-based)

    - `reacted_at: Optional[datetime]`

      When the reaction was added or removed

    - `reaction_id: Optional[str]`

      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.

    - `service: Optional[ServiceType]`

      Messaging service type

    - `sticker: Optional[Sticker]`

      Sticker attachment details when reaction_type is "sticker". Null for non-sticker reactions.

      - `file_name: Optional[str]`

        Filename of the sticker

      - `height: Optional[int]`

        Sticker image height in pixels

      - `mime_type: Optional[str]`

        MIME type of the sticker image

      - `url: Optional[str]`

        Presigned URL for downloading the sticker image (expires in 1 hour).

      - `width: Optional[int]`

        Sticker image width in pixels

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### reaction.removed

- `class ReactionRemovedWebhookEvent: …`

  Complete webhook payload for reaction.removed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: ReactionEventBase`

    Payload for reaction.removed webhook events

    - `is_from_me: bool`

      Whether this reaction was from the owner of the phone number (true) or from someone else (false)

    - `reaction_type: ReactionType`

      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.

      - `"love"`

      - `"like"`

      - `"dislike"`

      - `"laugh"`

      - `"emphasize"`

      - `"question"`

      - `"custom"`

      - `"sticker"`

    - `chat_id: Optional[str]`

      Chat identifier (UUID)

    - `custom_emoji: Optional[str]`

      The actual emoji when reaction_type is "custom". Null for standard tapbacks.

    - `from_: Optional[str]`

      DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.

    - `from_handle: Optional[ChatHandle]`

      The person who added/removed the reaction as a full handle object

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

    - `message_id: Optional[str]`

      Message identifier (UUID) that the reaction was added to or removed from

    - `part_index: Optional[int]`

      Index of the message part that was reacted to (0-based)

    - `reacted_at: Optional[datetime]`

      When the reaction was added or removed

    - `reaction_id: Optional[str]`

      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.

    - `service: Optional[ServiceType]`

      Messaging service type

    - `sticker: Optional[Sticker]`

      Sticker attachment details when reaction_type is "sticker". Null for non-sticker reactions.

      - `file_name: Optional[str]`

        Filename of the sticker

      - `height: Optional[int]`

        Sticker image height in pixels

      - `mime_type: Optional[str]`

        MIME type of the sticker image

      - `url: Optional[str]`

        Presigned URL for downloading the sticker image (expires in 1 hour).

      - `width: Optional[int]`

        Sticker image width in pixels

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.received

- `class PollReceivedWebhookEvent: …`

  Complete webhook payload for poll.received events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    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: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `created_at: datetime`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `message_id: str`

    - `poll: DataPoll`

      - `options: List[DataPollOption]`

        - `can_be_edited: bool`

        - `creator_handle: ChatHandle`

          The participant who added this option (poll creator for the initial options; whoever
          added later ones). On a poll.updated this differs from the event's `sender_handle`
          whenever a remote participant added the option. Null when unknown.

        - `option_id: str`

        - `text: str`

        - `voters: List[DataPollOptionVoter]`

          - `handle: str`

          - `voted_at: datetime`

      - `total_voters: int`

        Distinct participants across the whole poll.

    - `received_at: datetime`

    - `service: str`

    - `updated_at: datetime`

    - `sender_handle: Optional[ChatHandle]`

      The line that created the poll (is_me=false for an inbound poll).

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.sent

- `class PollSentWebhookEvent: …`

  Complete webhook payload for poll.sent events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    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: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `created_at: datetime`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `message_id: str`

    - `poll: DataPoll`

      - `options: List[DataPollOption]`

        - `can_be_edited: bool`

        - `creator_handle: ChatHandle`

          The participant who added this option (poll creator for the initial options; whoever
          added later ones). On a poll.updated this differs from the event's `sender_handle`
          whenever a remote participant added the option. Null when unknown.

        - `option_id: str`

        - `text: str`

        - `voters: List[DataPollOptionVoter]`

          - `handle: str`

          - `voted_at: datetime`

      - `total_voters: int`

        Distinct participants across the whole poll.

    - `service: str`

    - `updated_at: datetime`

    - `delivered_at: Optional[datetime]`

    - `read_at: Optional[datetime]`

    - `sender_handle: Optional[ChatHandle]`

      The handle that sent the poll.

    - `sent_at: Optional[datetime]`

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.delivered

- `class PollDeliveredWebhookEvent: …`

  Complete webhook payload for poll.delivered events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    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: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `created_at: datetime`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `message_id: str`

    - `poll: DataPoll`

      - `options: List[DataPollOption]`

        - `can_be_edited: bool`

        - `creator_handle: ChatHandle`

          The participant who added this option (poll creator for the initial options; whoever
          added later ones). On a poll.updated this differs from the event's `sender_handle`
          whenever a remote participant added the option. Null when unknown.

        - `option_id: str`

        - `text: str`

        - `voters: List[DataPollOptionVoter]`

          - `handle: str`

          - `voted_at: datetime`

      - `total_voters: int`

        Distinct participants across the whole poll.

    - `service: str`

    - `updated_at: datetime`

    - `delivered_at: Optional[datetime]`

    - `read_at: Optional[datetime]`

    - `sender_handle: Optional[ChatHandle]`

      The handle that sent the poll.

    - `sent_at: Optional[datetime]`

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.read

- `class PollReadWebhookEvent: …`

  Complete webhook payload for poll.read events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    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: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `created_at: datetime`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `message_id: str`

    - `poll: DataPoll`

      - `options: List[DataPollOption]`

        - `can_be_edited: bool`

        - `creator_handle: ChatHandle`

          The participant who added this option (poll creator for the initial options; whoever
          added later ones). On a poll.updated this differs from the event's `sender_handle`
          whenever a remote participant added the option. Null when unknown.

        - `option_id: str`

        - `text: str`

        - `voters: List[DataPollOptionVoter]`

          - `handle: str`

          - `voted_at: datetime`

      - `total_voters: int`

        Distinct participants across the whole poll.

    - `service: str`

    - `updated_at: datetime`

    - `delivered_at: Optional[datetime]`

    - `read_at: Optional[datetime]`

    - `sender_handle: Optional[ChatHandle]`

      The handle that sent the poll.

    - `sent_at: Optional[datetime]`

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.updated

- `class PollUpdatedWebhookEvent: …`

  Complete webhook payload for poll.updated events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for poll.updated (option(s) added — add-only).

    - `added_options: List[DataAddedOption]`

      Only the options this update added — never the ones the poll already had. Fetch the poll to read its full option set.

      - `can_be_edited: bool`

      - `creator_handle: ChatHandle`

        The participant who added this option (poll creator for the initial options; whoever
        added later ones). On a poll.updated this differs from the event's `sender_handle`
        whenever a remote participant added the option. Null when unknown.

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

      - `option_id: str`

      - `text: str`

      - `voters: List[DataAddedOptionVoter]`

        - `handle: str`

        - `voted_at: datetime`

    - `chat: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `message_id: str`

    - `sender_handle: ChatHandle`

      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.

    - `service: str`

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.failed

- `class PollFailedWebhookEvent: …`

  Complete webhook payload for poll.failed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    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: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `error: DataError`

      - `code: int`

        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.

      - `message: str`

    - `failed_at: datetime`

    - `message_id: str`

    - `poll: DataPoll`

      - `options: List[DataPollOption]`

        - `can_be_edited: bool`

        - `creator_handle: ChatHandle`

          The participant who added this option (poll creator for the initial options; whoever
          added later ones). On a poll.updated this differs from the event's `sender_handle`
          whenever a remote participant added the option. Null when unknown.

        - `option_id: str`

        - `text: str`

        - `voters: List[DataPollOptionVoter]`

          - `handle: str`

          - `voted_at: datetime`

      - `total_voters: int`

        Distinct participants across the whole poll.

    - `service: str`

    - `sender_handle: Optional[ChatHandle]`

      Null on failure (the send never landed).

    - `zero_retention: Optional[bool]`

      True when this poll was sent on a zero-day-retention line. `poll` is built from the same database read as poll.sent/delivered/read, so every option's `text` is empty.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.vote.added

- `class PollVoteAddedWebhookEvent: …`

  Complete webhook payload for poll.vote.added events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for poll.vote.added and poll.vote.removed (one option toggled).

    - `chat: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `message_id: str`

    - `option_id: str`

    - `sender_handle: ChatHandle`

      The voter — always present.

    - `service: str`

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.vote.removed

- `class PollVoteRemovedWebhookEvent: …`

  Complete webhook payload for poll.vote.removed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for poll.vote.added and poll.vote.removed (one option toggled).

    - `chat: DataChat`

      Chat info for poll webhook events.

      - `id: str`

      - `is_group: Optional[bool]`

      - `owner_handle: Optional[ChatHandle]`

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `direction: Literal["inbound", "outbound"]`

      - `"inbound"`

      - `"outbound"`

    - `message_id: str`

    - `option_id: str`

    - `sender_handle: ChatHandle`

      The voter — always present.

    - `service: str`

    - `zero_retention: Optional[bool]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### poll.reaction.added

- `class PollReactionAddedWebhookEvent: …`

  Complete webhook payload for poll.reaction.added events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: ReactionEventBase`

    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.

    - `is_from_me: bool`

      Whether this reaction was from the owner of the phone number (true) or from someone else (false)

    - `reaction_type: ReactionType`

      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.

      - `"love"`

      - `"like"`

      - `"dislike"`

      - `"laugh"`

      - `"emphasize"`

      - `"question"`

      - `"custom"`

      - `"sticker"`

    - `chat_id: Optional[str]`

      Chat identifier (UUID)

    - `custom_emoji: Optional[str]`

      The actual emoji when reaction_type is "custom". Null for standard tapbacks.

    - `from_: Optional[str]`

      DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.

    - `from_handle: Optional[ChatHandle]`

      The person who added/removed the reaction as a full handle object

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

    - `message_id: Optional[str]`

      Message identifier (UUID) that the reaction was added to or removed from

    - `part_index: Optional[int]`

      Index of the message part that was reacted to (0-based)

    - `reacted_at: Optional[datetime]`

      When the reaction was added or removed

    - `reaction_id: Optional[str]`

      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.

    - `service: Optional[ServiceType]`

      Messaging service type

    - `sticker: Optional[Sticker]`

      Sticker attachment details when reaction_type is "sticker". Null for non-sticker reactions.

      - `file_name: Optional[str]`

        Filename of the sticker

      - `height: Optional[int]`

        Sticker image height in pixels

      - `mime_type: Optional[str]`

        MIME type of the sticker image

      - `url: Optional[str]`

        Presigned URL for downloading the sticker image (expires in 1 hour).

      - `width: Optional[int]`

        Sticker image width in pixels

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### participant.added

- `class ParticipantAddedWebhookEvent: …`

  Complete webhook payload for participant.added events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for participant.added webhook events

    - `handle: str`

      DEPRECATED: Use participant instead. Handle (phone number or email address) of the added participant.

    - `added_at: Optional[datetime]`

      When the participant was added

    - `chat_id: Optional[str]`

      Chat identifier (UUID) of the group chat

    - `participant: Optional[ChatHandle]`

      The added participant as a full handle object

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### participant.removed

- `class ParticipantRemovedWebhookEvent: …`

  Complete webhook payload for participant.removed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for participant.removed webhook events

    - `handle: str`

      DEPRECATED: Use participant instead. Handle (phone number or email address) of the removed participant.

    - `chat_id: Optional[str]`

      Chat identifier (UUID) of the group chat

    - `participant: Optional[ChatHandle]`

      The removed participant as a full handle object

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

    - `removed_at: Optional[datetime]`

      When the participant was removed

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.created

- `class ChatCreatedWebhookEvent: …`

  Complete webhook payload for chat.created events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for chat.created webhook events. Matches GET /v3/chats/{chatId} response.

    - `id: str`

      Unique identifier for the chat

    - `created_at: datetime`

      When the chat was created

    - `display_name: Optional[str]`

      Display name for the chat. Defaults to a comma-separated list of recipient handles. Can be updated for group chats.

    - `handles: List[ChatHandle]`

      List of chat participants with full handle details. Always contains at least two handles (your phone number and the other participant).

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

    - `health_status: DataHealthStatus`

      **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

      - `doc_url: str`

        Deep-link to the relevant section of the Chat Health guide for this status.

      - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

        Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

        - `"HEALTHY"`

        - `"AT_RISK"`

        - `"CRITICAL"`

        - `"OPTED_OUT"`

      - `updated_at: datetime`

        When this status last changed.

    - `is_group: bool`

      Whether this is a group chat

    - `updated_at: datetime`

      When the chat was last updated

    - `service: Optional[ServiceType]`

      Messaging service type

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.group_name_updated

- `class ChatGroupNameUpdatedWebhookEvent: …`

  Complete webhook payload for chat.group_name_updated events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for chat.group_name_updated webhook events

    - `chat_id: str`

      Chat identifier (UUID) of the group chat

    - `updated_at: datetime`

      When the update occurred

    - `changed_by_handle: Optional[ChatHandle]`

      The handle who made the change.

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

    - `new_value: Optional[str]`

      New group name (null if the name was removed)

    - `old_value: Optional[str]`

      Previous group name (null if no previous name)

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.group_icon_updated

- `class ChatGroupIconUpdatedWebhookEvent: …`

  Complete webhook payload for chat.group_icon_updated events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for chat.group_icon_updated webhook events

    - `chat_id: str`

      Chat identifier (UUID) of the group chat

    - `updated_at: datetime`

      When the update occurred

    - `changed_by_handle: Optional[ChatHandle]`

      The handle who made the change.

      - `id: str`

        Unique identifier for this handle

      - `handle: str`

        Phone number (E.164) or email address of the participant

      - `joined_at: datetime`

        When this participant joined the chat

      - `service: ServiceType`

        Messaging service type

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

      - `is_me: Optional[bool]`

        Whether this handle belongs to the sender (your phone number)

      - `left_at: Optional[datetime]`

        When they left (if applicable)

      - `status: Optional[Literal["active", "left", "removed"]]`

        Participant status

        - `"active"`

        - `"left"`

        - `"removed"`

    - `new_value: Optional[str]`

      New icon URL (null if the icon was removed)

    - `old_value: Optional[str]`

      Previous icon URL (null if no previous icon)

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.group_name_update_failed

- `class ChatGroupNameUpdateFailedWebhookEvent: …`

  Complete webhook payload for chat.group_name_update_failed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Error details for chat.group_name_update_failed webhook events.
    See [WebhookErrorCode](#/components/schemas/WebhookErrorCode) for the full error code reference.

    - `chat_id: str`

      Chat identifier (UUID) of the group chat

    - `error_code: int`

      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.

    - `failed_at: datetime`

      When the failure was detected

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.group_icon_update_failed

- `class ChatGroupIconUpdateFailedWebhookEvent: …`

  Complete webhook payload for chat.group_icon_update_failed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Error details for chat.group_icon_update_failed webhook events.
    See [WebhookErrorCode](#/components/schemas/WebhookErrorCode) for the full error code reference.

    - `chat_id: str`

      Chat identifier (UUID) of the group chat

    - `error_code: int`

      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.

    - `failed_at: datetime`

      When the failure was detected

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.typing_indicator.started

- `class ChatTypingIndicatorStartedWebhookEvent: …`

  Complete webhook payload for chat.typing_indicator.started events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for chat.typing_indicator.started webhook events

    - `chat_id: str`

      Chat identifier

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.typing_indicator.stopped

- `class ChatTypingIndicatorStoppedWebhookEvent: …`

  Complete webhook payload for chat.typing_indicator.stopped events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for chat.typing_indicator.stopped webhook events

    - `chat_id: str`

      Chat identifier

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.background_updated

- `class ChatBackgroundUpdatedWebhookEvent: …`

  Complete webhook payload for chat.background_updated events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for chat.background_updated webhook events.

    - `chat: DataChat`

      Chat information

      - `id: str`

        Chat identifier

      - `is_group: Optional[bool]`

        Whether this is a group chat

      - `owner_handle: Optional[ChatHandle]`

        Your phone number's handle. Always has is_me=true.

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

          - `"iMessage"`

          - `"SMS"`

          - `"RCS"`

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

          - `"active"`

          - `"left"`

          - `"removed"`

    - `actor_handle: Optional[ChatHandle]`

      Who changed it. `is_me` is true when your own number set it.

    - `background: Optional[DataBackground]`

      A chat transcript background. Fields are populated per `type`.

      - `type: Literal["color", "dynamic", "photo"]`

        The background family.

        - `"color"`

        - `"dynamic"`

        - `"photo"`

      - `image_url: Optional[str]`

        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.

      - `shades: Optional[List[str]]`

        Color: the two gradient stops as hex, top then bottom.

      - `style: Optional[Literal["sky", "water", "aurora", "glitter"]]`

        Dynamic: the animated style.

        - `"sky"`

        - `"water"`

        - `"aurora"`

        - `"glitter"`

      - `variant: Optional[str]`

        Color: `custom` (the stored two colors) or a named swatch. Dynamic: the
        variant within the `style` (e.g. `sunrise`).

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### chat.background_update_failed

- `class ChatBackgroundUpdateFailedWebhookEvent: …`

  Complete webhook payload for chat.background_update_failed events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Error details for chat.background_update_failed webhook events.
    See [WebhookErrorCode](#/components/schemas/WebhookErrorCode) for the full error code reference.

    - `chat_id: str`

      Chat identifier (UUID) whose background update failed

    - `error_code: int`

      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.

    - `failed_at: datetime`

      When the failure was detected

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### contact_card.received

- `class ContactCardReceivedWebhookEvent: …`

  Complete webhook payload for contact_card.received events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    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.

    - `first_name: str`

      First name from the shared contact card

    - `last_name: str`

      Last name from the shared contact card (may be empty)

    - `owner_handle: str`

      Which of your lines they shared it with.

    - `sender_handle: str`

      The person who shared their card — a phone number or email address.

    - `media_url: Optional[str]`

      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.

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: WebhookEventType`

    Valid webhook event types that can be subscribed to.

    **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
    Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### phone_number.status_updated

- `class PhoneNumberStatusUpdatedWebhookEvent: …`

  Complete webhook payload for phone_number.status_updated events

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    Payload for phone_number.status_updated webhook events

    - `changed_at: datetime`

      When the status change occurred

    - `new_reputation: Literal["HEALTHY", "AT_RISK", "CRITICAL"]`

      The new line reputation

      - `"HEALTHY"`

      - `"AT_RISK"`

      - `"CRITICAL"`

    - `new_status: Literal["ACTIVE", "FLAGGED"]`

      The new service status

      - `"ACTIVE"`

      - `"FLAGGED"`

    - `phone_number: str`

      Phone number in E.164 format

    - `previous_reputation: Literal["HEALTHY", "AT_RISK", "CRITICAL"]`

      The previous line reputation

      - `"HEALTHY"`

      - `"AT_RISK"`

      - `"CRITICAL"`

    - `previous_status: Literal["ACTIVE", "FLAGGED"]`

      The previous service status

      - `"ACTIVE"`

      - `"FLAGGED"`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["message.sent", "message.received", "message.read", 43 more]`

    The type of event

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### connection.created

- `class ConnectionCreatedWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    The payment request, as returned by
    `GET /v3/payment_requests/{paymentRequestId}`.

    - `id: str`

      The payment request id.

    - `amount: int`

      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.

    - `checkout_url: str`

      URL the recipient opens to pay
      (`https://zero.linqapp.com/pay/{slug}?session=...`).

    - `created_at: datetime`

    - `currency: str`

    - `object: str`

    - `status: Literal["succeeded", "failed", "canceled", "expired"]`

      - `"succeeded"`

      - `"failed"`

      - `"canceled"`

      - `"expired"`

    - `description: Optional[str]`

    - `discount: Optional[DataDiscount]`

      Subscription mode — the discount Stripe applied, read back
      from the coupon. Absent when none was applied.

      - `coupon: Optional[str]`

      - `label: Optional[str]`

        Name of the coupon/promo code displayed to customers.

      - `promotion_code: Optional[str]`

    - `interval: Optional[Literal["day", "week", "month", "year"]]`

      Subscription mode — how often the subscription renews.

      - `"day"`

      - `"week"`

      - `"month"`

      - `"year"`

    - `interval_count: Optional[int]`

      Subscription mode — intervals per renewal.

    - `metadata: Optional[Dict[str, str]]`

    - `mode: Optional[Literal["payment", "subscription"]]`

      Whether the request collected a one-time charge or started a subscription.

      - `"payment"`

      - `"subscription"`

    - `natural: Optional[DataNatural]`

      Natural-rail join keys, present when `rail: natural`.

      - `payment_request_id: Optional[str]`

        The Natural payment request (`prq_...`).

      - `transaction_id: Optional[str]`

        The settled transaction (`txn_...`).

    - `price_id: Optional[str]`

      Subscription mode — the recurring price subscribed to.

    - `quantity: Optional[int]`

      Subscription mode — units of the price subscribed to.

    - `rail: Optional[Literal["stripe", "natural"]]`

      The rail this request settled on.

      - `"stripe"`

      - `"natural"`

    - `stripe: Optional[DataStripe]`

      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`.

      - `customer_id: Optional[str]`

        The Customer the request is attached to (`cus_...`).
        Always set in subscription mode; set in payment mode
        only when the request was created with a `customer_id`.

      - `payment_intent_id: Optional[str]`

        The PaymentIntent collected at checkout (`pi_...`).

      - `subscription_id: Optional[str]`

        Subscription mode — the Subscription (`sub_...`).

    - `trial_end: Optional[datetime]`

      Subscription mode — when the free trial ends and the first
      charge happens. On a trial request, `payment.succeeded`
      means the payment method was collected ($0 moved).

    - `updated_at: Optional[datetime]`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### connection.revoked

- `class ConnectionRevokedWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    The payment request, as returned by
    `GET /v3/payment_requests/{paymentRequestId}`.

    - `id: str`

      The payment request id.

    - `amount: int`

      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.

    - `checkout_url: str`

      URL the recipient opens to pay
      (`https://zero.linqapp.com/pay/{slug}?session=...`).

    - `created_at: datetime`

    - `currency: str`

    - `object: str`

    - `status: Literal["succeeded", "failed", "canceled", "expired"]`

      - `"succeeded"`

      - `"failed"`

      - `"canceled"`

      - `"expired"`

    - `description: Optional[str]`

    - `discount: Optional[DataDiscount]`

      Subscription mode — the discount Stripe applied, read back
      from the coupon. Absent when none was applied.

      - `coupon: Optional[str]`

      - `label: Optional[str]`

        Name of the coupon/promo code displayed to customers.

      - `promotion_code: Optional[str]`

    - `interval: Optional[Literal["day", "week", "month", "year"]]`

      Subscription mode — how often the subscription renews.

      - `"day"`

      - `"week"`

      - `"month"`

      - `"year"`

    - `interval_count: Optional[int]`

      Subscription mode — intervals per renewal.

    - `metadata: Optional[Dict[str, str]]`

    - `mode: Optional[Literal["payment", "subscription"]]`

      Whether the request collected a one-time charge or started a subscription.

      - `"payment"`

      - `"subscription"`

    - `natural: Optional[DataNatural]`

      Natural-rail join keys, present when `rail: natural`.

      - `payment_request_id: Optional[str]`

        The Natural payment request (`prq_...`).

      - `transaction_id: Optional[str]`

        The settled transaction (`txn_...`).

    - `price_id: Optional[str]`

      Subscription mode — the recurring price subscribed to.

    - `quantity: Optional[int]`

      Subscription mode — units of the price subscribed to.

    - `rail: Optional[Literal["stripe", "natural"]]`

      The rail this request settled on.

      - `"stripe"`

      - `"natural"`

    - `stripe: Optional[DataStripe]`

      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`.

      - `customer_id: Optional[str]`

        The Customer the request is attached to (`cus_...`).
        Always set in subscription mode; set in payment mode
        only when the request was created with a `customer_id`.

      - `payment_intent_id: Optional[str]`

        The PaymentIntent collected at checkout (`pi_...`).

      - `subscription_id: Optional[str]`

        Subscription mode — the Subscription (`sub_...`).

    - `trial_end: Optional[datetime]`

      Subscription mode — when the free trial ends and the first
      charge happens. On a trial request, `payment.succeeded`
      means the payment method was collected ($0 moved).

    - `updated_at: Optional[datetime]`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### location.sharing.started

- `class LocationSharingStartedWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    - `began_at: Optional[datetime]`

      When location sharing started. Always present: falls back to when the share was first observed if the device reported no start time.

    - `chat_id: Optional[str]`

      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.

    - `ends_at: Optional[datetime]`

      When location sharing will expire. Null when sharing indefinitely.

    - `shared_by: str`

      Phone number of the person sharing their location

    - `shared_with: str`

      Your phone number receiving the location

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["location.sharing.started", "message.sent", "message.received", 43 more]`

    - `"location.sharing.started"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.stopped"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### location.sharing.stopped

- `class LocationSharingStoppedWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    - `began_at: Optional[datetime]`

      When the sharing session started, matching began_at on its started event. Always present.

    - `chat_id: Optional[str]`

      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.

    - `ended_at: datetime`

      When the sharing session was observed to stop.

    - `shared_by: str`

      Phone number of the person who stopped sharing

    - `shared_with: str`

      Your phone number that was receiving the location

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["location.sharing.stopped", "message.sent", "message.received", 43 more]`

    - `"location.sharing.stopped"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### payment.authorized

- `class PaymentAuthorizedWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    The payment request, as returned by
    `GET /v3/payment_requests/{paymentRequestId}`.

    - `id: str`

      The payment request id.

    - `amount: int`

      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.

    - `checkout_url: str`

      URL the recipient opens to pay
      (`https://zero.linqapp.com/pay/{slug}?session=...`).

    - `created_at: datetime`

    - `currency: str`

    - `object: str`

    - `status: Literal["succeeded", "failed", "canceled", "expired"]`

      - `"succeeded"`

      - `"failed"`

      - `"canceled"`

      - `"expired"`

    - `description: Optional[str]`

    - `discount: Optional[DataDiscount]`

      Subscription mode — the discount Stripe applied, read back
      from the coupon. Absent when none was applied.

      - `coupon: Optional[str]`

      - `label: Optional[str]`

        Name of the coupon/promo code displayed to customers.

      - `promotion_code: Optional[str]`

    - `interval: Optional[Literal["day", "week", "month", "year"]]`

      Subscription mode — how often the subscription renews.

      - `"day"`

      - `"week"`

      - `"month"`

      - `"year"`

    - `interval_count: Optional[int]`

      Subscription mode — intervals per renewal.

    - `metadata: Optional[Dict[str, str]]`

    - `mode: Optional[Literal["payment", "subscription"]]`

      Whether the request collected a one-time charge or started a subscription.

      - `"payment"`

      - `"subscription"`

    - `natural: Optional[DataNatural]`

      Natural-rail join keys, present when `rail: natural`.

      - `payment_request_id: Optional[str]`

        The Natural payment request (`prq_...`).

      - `transaction_id: Optional[str]`

        The settled transaction (`txn_...`).

    - `price_id: Optional[str]`

      Subscription mode — the recurring price subscribed to.

    - `quantity: Optional[int]`

      Subscription mode — units of the price subscribed to.

    - `rail: Optional[Literal["stripe", "natural"]]`

      The rail this request settled on.

      - `"stripe"`

      - `"natural"`

    - `stripe: Optional[DataStripe]`

      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`.

      - `customer_id: Optional[str]`

        The Customer the request is attached to (`cus_...`).
        Always set in subscription mode; set in payment mode
        only when the request was created with a `customer_id`.

      - `payment_intent_id: Optional[str]`

        The PaymentIntent collected at checkout (`pi_...`).

      - `subscription_id: Optional[str]`

        Subscription mode — the Subscription (`sub_...`).

    - `trial_end: Optional[datetime]`

      Subscription mode — when the free trial ends and the first
      charge happens. On a trial request, `payment.succeeded`
      means the payment method was collected ($0 moved).

    - `updated_at: Optional[datetime]`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### payment.canceled

- `class PaymentCanceledWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    The payment request, as returned by
    `GET /v3/payment_requests/{paymentRequestId}`.

    - `id: str`

      The payment request id.

    - `amount: int`

      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.

    - `checkout_url: str`

      URL the recipient opens to pay
      (`https://zero.linqapp.com/pay/{slug}?session=...`).

    - `created_at: datetime`

    - `currency: str`

    - `object: str`

    - `status: Literal["succeeded", "failed", "canceled", "expired"]`

      - `"succeeded"`

      - `"failed"`

      - `"canceled"`

      - `"expired"`

    - `description: Optional[str]`

    - `discount: Optional[DataDiscount]`

      Subscription mode — the discount Stripe applied, read back
      from the coupon. Absent when none was applied.

      - `coupon: Optional[str]`

      - `label: Optional[str]`

        Name of the coupon/promo code displayed to customers.

      - `promotion_code: Optional[str]`

    - `interval: Optional[Literal["day", "week", "month", "year"]]`

      Subscription mode — how often the subscription renews.

      - `"day"`

      - `"week"`

      - `"month"`

      - `"year"`

    - `interval_count: Optional[int]`

      Subscription mode — intervals per renewal.

    - `metadata: Optional[Dict[str, str]]`

    - `mode: Optional[Literal["payment", "subscription"]]`

      Whether the request collected a one-time charge or started a subscription.

      - `"payment"`

      - `"subscription"`

    - `natural: Optional[DataNatural]`

      Natural-rail join keys, present when `rail: natural`.

      - `payment_request_id: Optional[str]`

        The Natural payment request (`prq_...`).

      - `transaction_id: Optional[str]`

        The settled transaction (`txn_...`).

    - `price_id: Optional[str]`

      Subscription mode — the recurring price subscribed to.

    - `quantity: Optional[int]`

      Subscription mode — units of the price subscribed to.

    - `rail: Optional[Literal["stripe", "natural"]]`

      The rail this request settled on.

      - `"stripe"`

      - `"natural"`

    - `stripe: Optional[DataStripe]`

      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`.

      - `customer_id: Optional[str]`

        The Customer the request is attached to (`cus_...`).
        Always set in subscription mode; set in payment mode
        only when the request was created with a `customer_id`.

      - `payment_intent_id: Optional[str]`

        The PaymentIntent collected at checkout (`pi_...`).

      - `subscription_id: Optional[str]`

        Subscription mode — the Subscription (`sub_...`).

    - `trial_end: Optional[datetime]`

      Subscription mode — when the free trial ends and the first
      charge happens. On a trial request, `payment.succeeded`
      means the payment method was collected ($0 moved).

    - `updated_at: Optional[datetime]`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### payment.declined

- `class PaymentDeclinedWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    The payment request, as returned by
    `GET /v3/payment_requests/{paymentRequestId}`.

    - `id: str`

      The payment request id.

    - `amount: int`

      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.

    - `checkout_url: str`

      URL the recipient opens to pay
      (`https://zero.linqapp.com/pay/{slug}?session=...`).

    - `created_at: datetime`

    - `currency: str`

    - `object: str`

    - `status: Literal["succeeded", "failed", "canceled", "expired"]`

      - `"succeeded"`

      - `"failed"`

      - `"canceled"`

      - `"expired"`

    - `description: Optional[str]`

    - `discount: Optional[DataDiscount]`

      Subscription mode — the discount Stripe applied, read back
      from the coupon. Absent when none was applied.

      - `coupon: Optional[str]`

      - `label: Optional[str]`

        Name of the coupon/promo code displayed to customers.

      - `promotion_code: Optional[str]`

    - `interval: Optional[Literal["day", "week", "month", "year"]]`

      Subscription mode — how often the subscription renews.

      - `"day"`

      - `"week"`

      - `"month"`

      - `"year"`

    - `interval_count: Optional[int]`

      Subscription mode — intervals per renewal.

    - `metadata: Optional[Dict[str, str]]`

    - `mode: Optional[Literal["payment", "subscription"]]`

      Whether the request collected a one-time charge or started a subscription.

      - `"payment"`

      - `"subscription"`

    - `natural: Optional[DataNatural]`

      Natural-rail join keys, present when `rail: natural`.

      - `payment_request_id: Optional[str]`

        The Natural payment request (`prq_...`).

      - `transaction_id: Optional[str]`

        The settled transaction (`txn_...`).

    - `price_id: Optional[str]`

      Subscription mode — the recurring price subscribed to.

    - `quantity: Optional[int]`

      Subscription mode — units of the price subscribed to.

    - `rail: Optional[Literal["stripe", "natural"]]`

      The rail this request settled on.

      - `"stripe"`

      - `"natural"`

    - `stripe: Optional[DataStripe]`

      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`.

      - `customer_id: Optional[str]`

        The Customer the request is attached to (`cus_...`).
        Always set in subscription mode; set in payment mode
        only when the request was created with a `customer_id`.

      - `payment_intent_id: Optional[str]`

        The PaymentIntent collected at checkout (`pi_...`).

      - `subscription_id: Optional[str]`

        Subscription mode — the Subscription (`sub_...`).

    - `trial_end: Optional[datetime]`

      Subscription mode — when the free trial ends and the first
      charge happens. On a trial request, `payment.succeeded`
      means the payment method was collected ($0 moved).

    - `updated_at: Optional[datetime]`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### payment.expired

- `class PaymentExpiredWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    The payment request, as returned by
    `GET /v3/payment_requests/{paymentRequestId}`.

    - `id: str`

      The payment request id.

    - `amount: int`

      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.

    - `checkout_url: str`

      URL the recipient opens to pay
      (`https://zero.linqapp.com/pay/{slug}?session=...`).

    - `created_at: datetime`

    - `currency: str`

    - `object: str`

    - `status: Literal["succeeded", "failed", "canceled", "expired"]`

      - `"succeeded"`

      - `"failed"`

      - `"canceled"`

      - `"expired"`

    - `description: Optional[str]`

    - `discount: Optional[DataDiscount]`

      Subscription mode — the discount Stripe applied, read back
      from the coupon. Absent when none was applied.

      - `coupon: Optional[str]`

      - `label: Optional[str]`

        Name of the coupon/promo code displayed to customers.

      - `promotion_code: Optional[str]`

    - `interval: Optional[Literal["day", "week", "month", "year"]]`

      Subscription mode — how often the subscription renews.

      - `"day"`

      - `"week"`

      - `"month"`

      - `"year"`

    - `interval_count: Optional[int]`

      Subscription mode — intervals per renewal.

    - `metadata: Optional[Dict[str, str]]`

    - `mode: Optional[Literal["payment", "subscription"]]`

      Whether the request collected a one-time charge or started a subscription.

      - `"payment"`

      - `"subscription"`

    - `natural: Optional[DataNatural]`

      Natural-rail join keys, present when `rail: natural`.

      - `payment_request_id: Optional[str]`

        The Natural payment request (`prq_...`).

      - `transaction_id: Optional[str]`

        The settled transaction (`txn_...`).

    - `price_id: Optional[str]`

      Subscription mode — the recurring price subscribed to.

    - `quantity: Optional[int]`

      Subscription mode — units of the price subscribed to.

    - `rail: Optional[Literal["stripe", "natural"]]`

      The rail this request settled on.

      - `"stripe"`

      - `"natural"`

    - `stripe: Optional[DataStripe]`

      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`.

      - `customer_id: Optional[str]`

        The Customer the request is attached to (`cus_...`).
        Always set in subscription mode; set in payment mode
        only when the request was created with a `customer_id`.

      - `payment_intent_id: Optional[str]`

        The PaymentIntent collected at checkout (`pi_...`).

      - `subscription_id: Optional[str]`

        Subscription mode — the Subscription (`sub_...`).

    - `trial_end: Optional[datetime]`

      Subscription mode — when the free trial ends and the first
      charge happens. On a trial request, `payment.succeeded`
      means the payment method was collected ($0 moved).

    - `updated_at: Optional[datetime]`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### payment.succeeded

- `class PaymentSucceededWebhookEvent: …`

  - `api_version: str`

    API version for the webhook payload format

  - `created_at: datetime`

    When the event was created

  - `data: Data`

    The payment request, as returned by
    `GET /v3/payment_requests/{paymentRequestId}`.

    - `id: str`

      The payment request id.

    - `amount: int`

      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.

    - `checkout_url: str`

      URL the recipient opens to pay
      (`https://zero.linqapp.com/pay/{slug}?session=...`).

    - `created_at: datetime`

    - `currency: str`

    - `object: str`

    - `status: Literal["succeeded", "failed", "canceled", "expired"]`

      - `"succeeded"`

      - `"failed"`

      - `"canceled"`

      - `"expired"`

    - `description: Optional[str]`

    - `discount: Optional[DataDiscount]`

      Subscription mode — the discount Stripe applied, read back
      from the coupon. Absent when none was applied.

      - `coupon: Optional[str]`

      - `label: Optional[str]`

        Name of the coupon/promo code displayed to customers.

      - `promotion_code: Optional[str]`

    - `interval: Optional[Literal["day", "week", "month", "year"]]`

      Subscription mode — how often the subscription renews.

      - `"day"`

      - `"week"`

      - `"month"`

      - `"year"`

    - `interval_count: Optional[int]`

      Subscription mode — intervals per renewal.

    - `metadata: Optional[Dict[str, str]]`

    - `mode: Optional[Literal["payment", "subscription"]]`

      Whether the request collected a one-time charge or started a subscription.

      - `"payment"`

      - `"subscription"`

    - `natural: Optional[DataNatural]`

      Natural-rail join keys, present when `rail: natural`.

      - `payment_request_id: Optional[str]`

        The Natural payment request (`prq_...`).

      - `transaction_id: Optional[str]`

        The settled transaction (`txn_...`).

    - `price_id: Optional[str]`

      Subscription mode — the recurring price subscribed to.

    - `quantity: Optional[int]`

      Subscription mode — units of the price subscribed to.

    - `rail: Optional[Literal["stripe", "natural"]]`

      The rail this request settled on.

      - `"stripe"`

      - `"natural"`

    - `stripe: Optional[DataStripe]`

      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`.

      - `customer_id: Optional[str]`

        The Customer the request is attached to (`cus_...`).
        Always set in subscription mode; set in payment mode
        only when the request was created with a `customer_id`.

      - `payment_intent_id: Optional[str]`

        The PaymentIntent collected at checkout (`pi_...`).

      - `subscription_id: Optional[str]`

        Subscription mode — the Subscription (`sub_...`).

    - `trial_end: Optional[datetime]`

      Subscription mode — when the free trial ends and the first
      charge happens. On a trial request, `payment.succeeded`
      means the payment method was collected ($0 moved).

    - `updated_at: Optional[datetime]`

  - `event_id: str`

    Unique identifier for this event (for deduplication)

  - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

    - `"payment.succeeded"`

    - `"payment.canceled"`

    - `"payment.expired"`

    - `"message.sent"`

    - `"message.received"`

    - `"message.read"`

    - `"message.delivered"`

    - `"message.failed"`

    - `"message.edited"`

    - `"reaction.added"`

    - `"reaction.removed"`

    - `"poll.received"`

    - `"poll.failed"`

    - `"poll.sent"`

    - `"poll.delivered"`

    - `"poll.read"`

    - `"poll.updated"`

    - `"poll.vote.added"`

    - `"poll.vote.removed"`

    - `"poll.reaction.added"`

    - `"participant.added"`

    - `"participant.removed"`

    - `"chat.created"`

    - `"chat.group_name_updated"`

    - `"chat.group_icon_updated"`

    - `"chat.group_name_update_failed"`

    - `"chat.group_icon_update_failed"`

    - `"chat.background_updated"`

    - `"chat.background_update_failed"`

    - `"chat.typing_indicator.started"`

    - `"chat.typing_indicator.stopped"`

    - `"phone_number.status_updated"`

    - `"contact_card.received"`

    - `"call.initiated"`

    - `"call.ringing"`

    - `"call.answered"`

    - `"call.ended"`

    - `"call.failed"`

    - `"call.declined"`

    - `"call.no_answer"`

    - `"location.sharing.started"`

    - `"location.sharing.stopped"`

    - `"payment.declined"`

    - `"payment.authorized"`

    - `"connection.created"`

    - `"connection.revoked"`

  - `partner_id: str`

    Partner identifier. Present on all webhooks for cross-referencing.

  - `trace_id: str`

    Trace ID for debugging and correlation across systems.

  - `webhook_version: str`

    Date-based webhook payload version.
    Determined by the `?version=` query parameter in your webhook subscription URL.
    If no version parameter is specified, defaults based on subscription creation date.

### Unwrap Webhook Event

- `UnwrapWebhookEvent`

  Complete webhook payload for message.sent events (2026-02-03 format)

  - `class MessageSentWebhookEvent: …`

    Complete webhook payload for message.sent events (2026-02-03 format)

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: MessageEventV2`

      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

      - `id: str`

        Message identifier

      - `chat: Chat`

        Chat information

        - `id: str`

          Chat identifier

        - `health_status: ChatHealthStatus`

          **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

          - `doc_url: str`

            Deep-link to the relevant section of the Chat Health guide for this status.

          - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

            Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

            - `"HEALTHY"`

            - `"AT_RISK"`

            - `"CRITICAL"`

            - `"OPTED_OUT"`

          - `updated_at: datetime`

            When this status last changed.

        - `is_group: Optional[bool]`

          Whether this is a group chat

        - `owner_handle: Optional[ChatHandle]`

          Your phone number's handle. Always has is_me=true.

          - `id: str`

            Unique identifier for this handle

          - `handle: str`

            Phone number (E.164) or email address of the participant

          - `joined_at: datetime`

            When this participant joined the chat

          - `service: ServiceType`

            Messaging service type

            - `"iMessage"`

            - `"SMS"`

            - `"RCS"`

          - `is_me: Optional[bool]`

            Whether this handle belongs to the sender (your phone number)

          - `left_at: Optional[datetime]`

            When they left (if applicable)

          - `status: Optional[Literal["active", "left", "removed"]]`

            Participant status

            - `"active"`

            - `"left"`

            - `"removed"`

      - `direction: Literal["inbound", "outbound"]`

        Message direction - "outbound" if sent by you, "inbound" if received

        - `"inbound"`

        - `"outbound"`

      - `parts: List[Part]`

        Message parts (text and/or media)

        - `class SchemasTextPartResponse: …`

          A text message part

          - `type: Literal["text"]`

            Indicates this is a text message part

            - `"text"`

          - `value: str`

            The text content

          - `mention: Optional[str]`

            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.

          - `mention_range: Optional[List[int]]`

            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[List[Mention]]`

            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.

            - `handle: str`

              Address of the mentioned participant, exactly as the device recorded it — an E.164
              phone number or an email address.

            - `is_me: bool`

              Whether the mentioned participant is this line.

            - `range: List[int]`

              Character range `[start, end)` in `value` highlighted as this mention.
              *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

          - `text_decorations: Optional[List[TextDecoration]]`

            Text decorations applied to character ranges in the value

            - `range: List[int]`

              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.*

            - `animation: Optional[Literal["big", "small", "shake", 5 more]]`

              Animated text effect to apply. Mutually exclusive with `style`.

              - `"big"`

              - `"small"`

              - `"shake"`

              - `"nod"`

              - `"explode"`

              - `"ripple"`

              - `"bloom"`

              - `"jitter"`

            - `style: Optional[Literal["bold", "italic", "strikethrough", "underline"]]`

              Text style to apply. Mutually exclusive with `animation`.

              - `"bold"`

              - `"italic"`

              - `"strikethrough"`

              - `"underline"`

        - `class SchemasMediaPartResponse: …`

          A media attachment part

          - `id: str`

            Unique attachment identifier

          - `filename: str`

            Original filename

          - `mime_type: str`

            MIME type of the file

          - `size_bytes: int`

            File size in bytes

          - `type: Literal["media"]`

            Indicates this is a media attachment part

            - `"media"`

          - `url: str`

            Presigned URL for downloading the attachment (expires in 1 hour).

        - `class PartSchemasLinkPartResponse: …`

          A rich link preview part

          - `type: Literal["link"]`

            Indicates this is a rich link preview part

            - `"link"`

          - `value: str`

            The URL

        - `class PartSchemasIMessageAppPartResponse: …`

          An iMessage app card part.

          - `app: PartSchemasIMessageAppPartResponseApp`

            Identifies the iMessage app (Messages app extension) that backs the card.

            - `bundle_id: str`

              Bundle identifier of the Messages app extension.

            - `name: str`

              Display name of the app.

            - `team_id: str`

              The app's 10-character team identifier.

            - `app_store_id: Optional[int]`

              The owning app's App Store id, when known.

          - `layout: PartSchemasIMessageAppPartResponseLayout`

            Visible layout of the card.

            - `caption: Optional[str]`

              Primary label, top-left and bold.

            - `subcaption: Optional[str]`

              Secondary label, below caption on the left.

            - `trailing_caption: Optional[str]`

              Label shown top-right.

            - `trailing_subcaption: Optional[str]`

              Label shown below trailing_caption.

          - `type: Literal["imessage_app"]`

            Indicates this is an iMessage app card part.

            - `"imessage_app"`

          - `url: str`

            The URL the recipient's app opens when the user taps the card.

          - `fallback_text: Optional[str]`

            Fallback text for surfaces that cannot render the card.

        - `class PartSchemasAppClipPartResponse: …`

          An Apple Pay App Clip payment card part

          - `type: Literal["app_clip"]`

            Indicates this is an App Clip payment card part

            - `"app_clip"`

          - `value: str`

            The checkout link the card opens

          - `description: Optional[str]`

            The card's summary line, composed by Linq from the checkout session

          - `image_url: Optional[str]`

            The card's preview image

          - `title: Optional[str]`

            The card's headline, composed by Linq from the checkout session

      - `sender_handle: ChatHandle`

        The handle that sent this message

      - `service: ServiceType`

        Messaging service type

      - `delivered_at: Optional[datetime]`

        When the message was delivered. Null if not yet delivered.

      - `effect: Optional[SchemasMessageEffect]`

        iMessage effect applied to a message (screen or bubble animation)

        - `name: Optional[str]`

          Effect name (confetti, fireworks, slam, gentle, etc.)

        - `type: Optional[Literal["screen", "bubble"]]`

          Effect category

          - `"screen"`

          - `"bubble"`

      - `idempotency_key: Optional[str]`

        Idempotency key for deduplication of outbound messages.

      - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

        Preferred messaging service type. Includes "auto" for default fallback behavior.

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

        - `"auto"`

      - `read_at: Optional[datetime]`

        When the message was read. Null if not yet read.

      - `reconciled_at: Optional[datetime]`

        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).

      - `reply_to: Optional[ReplyTo]`

        Reference to the message this is replying to (for threaded replies)

        - `message_id: Optional[str]`

          ID of the message being replied to

        - `part_index: Optional[int]`

          Index of the part being replied to

      - `sent_at: Optional[datetime]`

        When the message was sent. Null if not yet sent.

      - `zero_retention: Optional[bool]`

        True when this message was sent on a zero-day-retention line. `parts` is always empty in that case — Linq never persists this message's content, so there is nothing to include here, not even a count or type of what was sent.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class MessageReceivedWebhookEvent: …`

    Complete webhook payload for message.received events (2026-02-03 format)

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: MessageEventV2`

      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

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class MessageReadWebhookEvent: …`

    Complete webhook payload for message.read events (2026-02-03 format)

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: MessageEventV2`

      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

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class MessageDeliveredWebhookEvent: …`

    Complete webhook payload for message.delivered events (2026-02-03 format)

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: MessageEventV2`

      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

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class MessageFailedWebhookEvent: …`

    Complete webhook payload for message.failed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Error details for message.failed webhook events.
      See [WebhookErrorCode](#/components/schemas/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.

      - `code: int`

        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.

      - `failed_at: datetime`

        When the failure was detected

      - `chat_id: Optional[str]`

        Chat identifier (UUID)

      - `detail_code: Optional[int]`

        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.

      - `message_id: Optional[str]`

        Message identifier (UUID)

      - `preferred_service: Optional[Literal["iMessage", "SMS", "RCS", "auto"]]`

        Preferred messaging service type. Includes "auto" for default fallback behavior.

        - `"iMessage"`

        - `"SMS"`

        - `"RCS"`

        - `"auto"`

      - `reason: Optional[str]`

        Human-readable description of the failure

      - `service: Optional[ServiceType]`

        Messaging service type

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class MessageEditedWebhookEvent: …`

    Complete webhook payload for message.edited events (2026-02-03 format only)

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      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"`.

      - `id: str`

        Message identifier

      - `chat: DataChat`

        Chat context

        - `id: str`

          Chat identifier

        - `health_status: DataChatHealthStatus`

          **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

          - `doc_url: str`

            Deep-link to the relevant section of the Chat Health guide for this status.

          - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

            Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

            - `"HEALTHY"`

            - `"AT_RISK"`

            - `"CRITICAL"`

            - `"OPTED_OUT"`

          - `updated_at: datetime`

            When this status last changed.

        - `is_group: bool`

          Whether this is a group chat

        - `owner_handle: ChatHandle`

          The handle that owns this chat (your phone number)

      - `direction: Literal["outbound", "inbound"]`

        "outbound" if you sent the original message, "inbound" if you received it

        - `"outbound"`

        - `"inbound"`

      - `edited_at: datetime`

        When the edit occurred

      - `part: DataPart`

        The edited part

        - `index: int`

          Zero-based index of the edited part within the message

        - `text: str`

          New text content of the part

      - `sender_handle: ChatHandle`

        The handle that sent (and edited) this message

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ReactionAddedWebhookEvent: …`

    Complete webhook payload for reaction.added events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: ReactionEventBase`

      Payload for reaction.added webhook events

      - `is_from_me: bool`

        Whether this reaction was from the owner of the phone number (true) or from someone else (false)

      - `reaction_type: ReactionType`

        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.

        - `"love"`

        - `"like"`

        - `"dislike"`

        - `"laugh"`

        - `"emphasize"`

        - `"question"`

        - `"custom"`

        - `"sticker"`

      - `chat_id: Optional[str]`

        Chat identifier (UUID)

      - `custom_emoji: Optional[str]`

        The actual emoji when reaction_type is "custom". Null for standard tapbacks.

      - `from_: Optional[str]`

        DEPRECATED: Use from_handle instead. Phone number or email address of the person who added/removed the reaction.

      - `from_handle: Optional[ChatHandle]`

        The person who added/removed the reaction as a full handle object

      - `message_id: Optional[str]`

        Message identifier (UUID) that the reaction was added to or removed from

      - `part_index: Optional[int]`

        Index of the message part that was reacted to (0-based)

      - `reacted_at: Optional[datetime]`

        When the reaction was added or removed

      - `reaction_id: Optional[str]`

        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.

      - `service: Optional[ServiceType]`

        Messaging service type

      - `sticker: Optional[Sticker]`

        Sticker attachment details when reaction_type is "sticker". Null for non-sticker reactions.

        - `file_name: Optional[str]`

          Filename of the sticker

        - `height: Optional[int]`

          Sticker image height in pixels

        - `mime_type: Optional[str]`

          MIME type of the sticker image

        - `url: Optional[str]`

          Presigned URL for downloading the sticker image (expires in 1 hour).

        - `width: Optional[int]`

          Sticker image width in pixels

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ReactionRemovedWebhookEvent: …`

    Complete webhook payload for reaction.removed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: ReactionEventBase`

      Payload for reaction.removed webhook events

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollReceivedWebhookEvent: …`

    Complete webhook payload for poll.received events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      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: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `created_at: datetime`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `message_id: str`

      - `poll: DataPoll`

        - `options: List[DataPollOption]`

          - `can_be_edited: bool`

          - `creator_handle: ChatHandle`

            The participant who added this option (poll creator for the initial options; whoever
            added later ones). On a poll.updated this differs from the event's `sender_handle`
            whenever a remote participant added the option. Null when unknown.

          - `option_id: str`

          - `text: str`

          - `voters: List[DataPollOptionVoter]`

            - `handle: str`

            - `voted_at: datetime`

        - `total_voters: int`

          Distinct participants across the whole poll.

      - `received_at: datetime`

      - `service: str`

      - `updated_at: datetime`

      - `sender_handle: Optional[ChatHandle]`

        The line that created the poll (is_me=false for an inbound poll).

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollSentWebhookEvent: …`

    Complete webhook payload for poll.sent events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      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: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `created_at: datetime`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `message_id: str`

      - `poll: DataPoll`

        - `options: List[DataPollOption]`

          - `can_be_edited: bool`

          - `creator_handle: ChatHandle`

            The participant who added this option (poll creator for the initial options; whoever
            added later ones). On a poll.updated this differs from the event's `sender_handle`
            whenever a remote participant added the option. Null when unknown.

          - `option_id: str`

          - `text: str`

          - `voters: List[DataPollOptionVoter]`

            - `handle: str`

            - `voted_at: datetime`

        - `total_voters: int`

          Distinct participants across the whole poll.

      - `service: str`

      - `updated_at: datetime`

      - `delivered_at: Optional[datetime]`

      - `read_at: Optional[datetime]`

      - `sender_handle: Optional[ChatHandle]`

        The handle that sent the poll.

      - `sent_at: Optional[datetime]`

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollDeliveredWebhookEvent: …`

    Complete webhook payload for poll.delivered events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      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: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `created_at: datetime`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `message_id: str`

      - `poll: DataPoll`

        - `options: List[DataPollOption]`

          - `can_be_edited: bool`

          - `creator_handle: ChatHandle`

            The participant who added this option (poll creator for the initial options; whoever
            added later ones). On a poll.updated this differs from the event's `sender_handle`
            whenever a remote participant added the option. Null when unknown.

          - `option_id: str`

          - `text: str`

          - `voters: List[DataPollOptionVoter]`

            - `handle: str`

            - `voted_at: datetime`

        - `total_voters: int`

          Distinct participants across the whole poll.

      - `service: str`

      - `updated_at: datetime`

      - `delivered_at: Optional[datetime]`

      - `read_at: Optional[datetime]`

      - `sender_handle: Optional[ChatHandle]`

        The handle that sent the poll.

      - `sent_at: Optional[datetime]`

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollReadWebhookEvent: …`

    Complete webhook payload for poll.read events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      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: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `created_at: datetime`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `message_id: str`

      - `poll: DataPoll`

        - `options: List[DataPollOption]`

          - `can_be_edited: bool`

          - `creator_handle: ChatHandle`

            The participant who added this option (poll creator for the initial options; whoever
            added later ones). On a poll.updated this differs from the event's `sender_handle`
            whenever a remote participant added the option. Null when unknown.

          - `option_id: str`

          - `text: str`

          - `voters: List[DataPollOptionVoter]`

            - `handle: str`

            - `voted_at: datetime`

        - `total_voters: int`

          Distinct participants across the whole poll.

      - `service: str`

      - `updated_at: datetime`

      - `delivered_at: Optional[datetime]`

      - `read_at: Optional[datetime]`

      - `sender_handle: Optional[ChatHandle]`

        The handle that sent the poll.

      - `sent_at: Optional[datetime]`

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollUpdatedWebhookEvent: …`

    Complete webhook payload for poll.updated events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for poll.updated (option(s) added — add-only).

      - `added_options: List[DataAddedOption]`

        Only the options this update added — never the ones the poll already had. Fetch the poll to read its full option set.

        - `can_be_edited: bool`

        - `creator_handle: ChatHandle`

          The participant who added this option (poll creator for the initial options; whoever
          added later ones). On a poll.updated this differs from the event's `sender_handle`
          whenever a remote participant added the option. Null when unknown.

        - `option_id: str`

        - `text: str`

        - `voters: List[DataAddedOptionVoter]`

          - `handle: str`

          - `voted_at: datetime`

      - `chat: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `message_id: str`

      - `sender_handle: ChatHandle`

        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.

      - `service: str`

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollFailedWebhookEvent: …`

    Complete webhook payload for poll.failed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      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: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `error: DataError`

        - `code: int`

          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.

        - `message: str`

      - `failed_at: datetime`

      - `message_id: str`

      - `poll: DataPoll`

        - `options: List[DataPollOption]`

          - `can_be_edited: bool`

          - `creator_handle: ChatHandle`

            The participant who added this option (poll creator for the initial options; whoever
            added later ones). On a poll.updated this differs from the event's `sender_handle`
            whenever a remote participant added the option. Null when unknown.

          - `option_id: str`

          - `text: str`

          - `voters: List[DataPollOptionVoter]`

            - `handle: str`

            - `voted_at: datetime`

        - `total_voters: int`

          Distinct participants across the whole poll.

      - `service: str`

      - `sender_handle: Optional[ChatHandle]`

        Null on failure (the send never landed).

      - `zero_retention: Optional[bool]`

        True when this poll was sent on a zero-day-retention line. `poll` is built from the same database read as poll.sent/delivered/read, so every option's `text` is empty.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollVoteAddedWebhookEvent: …`

    Complete webhook payload for poll.vote.added events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for poll.vote.added and poll.vote.removed (one option toggled).

      - `chat: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `message_id: str`

      - `option_id: str`

      - `sender_handle: ChatHandle`

        The voter — always present.

      - `service: str`

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollVoteRemovedWebhookEvent: …`

    Complete webhook payload for poll.vote.removed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for poll.vote.added and poll.vote.removed (one option toggled).

      - `chat: DataChat`

        Chat info for poll webhook events.

        - `id: str`

        - `is_group: Optional[bool]`

        - `owner_handle: Optional[ChatHandle]`

      - `direction: Literal["inbound", "outbound"]`

        - `"inbound"`

        - `"outbound"`

      - `message_id: str`

      - `option_id: str`

      - `sender_handle: ChatHandle`

        The voter — always present.

      - `service: str`

      - `zero_retention: Optional[bool]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PollReactionAddedWebhookEvent: …`

    Complete webhook payload for poll.reaction.added events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: ReactionEventBase`

      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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ParticipantAddedWebhookEvent: …`

    Complete webhook payload for participant.added events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for participant.added webhook events

      - `handle: str`

        DEPRECATED: Use participant instead. Handle (phone number or email address) of the added participant.

      - `added_at: Optional[datetime]`

        When the participant was added

      - `chat_id: Optional[str]`

        Chat identifier (UUID) of the group chat

      - `participant: Optional[ChatHandle]`

        The added participant as a full handle object

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ParticipantRemovedWebhookEvent: …`

    Complete webhook payload for participant.removed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for participant.removed webhook events

      - `handle: str`

        DEPRECATED: Use participant instead. Handle (phone number or email address) of the removed participant.

      - `chat_id: Optional[str]`

        Chat identifier (UUID) of the group chat

      - `participant: Optional[ChatHandle]`

        The removed participant as a full handle object

      - `removed_at: Optional[datetime]`

        When the participant was removed

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatCreatedWebhookEvent: …`

    Complete webhook payload for chat.created events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for chat.created webhook events. Matches GET /v3/chats/{chatId} response.

      - `id: str`

        Unique identifier for the chat

      - `created_at: datetime`

        When the chat was created

      - `display_name: Optional[str]`

        Display name for the chat. Defaults to a comma-separated list of recipient handles. Can be updated for group chats.

      - `handles: List[ChatHandle]`

        List of chat participants with full handle details. Always contains at least two handles (your phone number and the other participant).

        - `id: str`

          Unique identifier for this handle

        - `handle: str`

          Phone number (E.164) or email address of the participant

        - `joined_at: datetime`

          When this participant joined the chat

        - `service: ServiceType`

          Messaging service type

        - `is_me: Optional[bool]`

          Whether this handle belongs to the sender (your phone number)

        - `left_at: Optional[datetime]`

          When they left (if applicable)

        - `status: Optional[Literal["active", "left", "removed"]]`

          Participant status

      - `health_status: DataHealthStatus`

        **[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](/channel/imessage/guides/chats/chat-health) for what each status means and how to react.

        - `doc_url: str`

          Deep-link to the relevant section of the Chat Health guide for this status.

        - `status: Literal["HEALTHY", "AT_RISK", "CRITICAL", "OPTED_OUT"]`

          Current health bucket for the chat. See the [Chat Health guide](/channel/imessage/guides/chats/chat-health) 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.

          - `"HEALTHY"`

          - `"AT_RISK"`

          - `"CRITICAL"`

          - `"OPTED_OUT"`

        - `updated_at: datetime`

          When this status last changed.

      - `is_group: bool`

        Whether this is a group chat

      - `updated_at: datetime`

        When the chat was last updated

      - `service: Optional[ServiceType]`

        Messaging service type

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatGroupNameUpdatedWebhookEvent: …`

    Complete webhook payload for chat.group_name_updated events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for chat.group_name_updated webhook events

      - `chat_id: str`

        Chat identifier (UUID) of the group chat

      - `updated_at: datetime`

        When the update occurred

      - `changed_by_handle: Optional[ChatHandle]`

        The handle who made the change.

      - `new_value: Optional[str]`

        New group name (null if the name was removed)

      - `old_value: Optional[str]`

        Previous group name (null if no previous name)

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatGroupIconUpdatedWebhookEvent: …`

    Complete webhook payload for chat.group_icon_updated events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for chat.group_icon_updated webhook events

      - `chat_id: str`

        Chat identifier (UUID) of the group chat

      - `updated_at: datetime`

        When the update occurred

      - `changed_by_handle: Optional[ChatHandle]`

        The handle who made the change.

      - `new_value: Optional[str]`

        New icon URL (null if the icon was removed)

      - `old_value: Optional[str]`

        Previous icon URL (null if no previous icon)

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatGroupNameUpdateFailedWebhookEvent: …`

    Complete webhook payload for chat.group_name_update_failed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Error details for chat.group_name_update_failed webhook events.
      See [WebhookErrorCode](#/components/schemas/WebhookErrorCode) for the full error code reference.

      - `chat_id: str`

        Chat identifier (UUID) of the group chat

      - `error_code: int`

        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.

      - `failed_at: datetime`

        When the failure was detected

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatGroupIconUpdateFailedWebhookEvent: …`

    Complete webhook payload for chat.group_icon_update_failed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Error details for chat.group_icon_update_failed webhook events.
      See [WebhookErrorCode](#/components/schemas/WebhookErrorCode) for the full error code reference.

      - `chat_id: str`

        Chat identifier (UUID) of the group chat

      - `error_code: int`

        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.

      - `failed_at: datetime`

        When the failure was detected

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatTypingIndicatorStartedWebhookEvent: …`

    Complete webhook payload for chat.typing_indicator.started events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for chat.typing_indicator.started webhook events

      - `chat_id: str`

        Chat identifier

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatTypingIndicatorStoppedWebhookEvent: …`

    Complete webhook payload for chat.typing_indicator.stopped events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for chat.typing_indicator.stopped webhook events

      - `chat_id: str`

        Chat identifier

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatBackgroundUpdatedWebhookEvent: …`

    Complete webhook payload for chat.background_updated events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for chat.background_updated webhook events.

      - `chat: DataChat`

        Chat information

        - `id: str`

          Chat identifier

        - `is_group: Optional[bool]`

          Whether this is a group chat

        - `owner_handle: Optional[ChatHandle]`

          Your phone number's handle. Always has is_me=true.

      - `actor_handle: Optional[ChatHandle]`

        Who changed it. `is_me` is true when your own number set it.

      - `background: Optional[DataBackground]`

        A chat transcript background. Fields are populated per `type`.

        - `type: Literal["color", "dynamic", "photo"]`

          The background family.

          - `"color"`

          - `"dynamic"`

          - `"photo"`

        - `image_url: Optional[str]`

          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.

        - `shades: Optional[List[str]]`

          Color: the two gradient stops as hex, top then bottom.

        - `style: Optional[Literal["sky", "water", "aurora", "glitter"]]`

          Dynamic: the animated style.

          - `"sky"`

          - `"water"`

          - `"aurora"`

          - `"glitter"`

        - `variant: Optional[str]`

          Color: `custom` (the stored two colors) or a named swatch. Dynamic: the
          variant within the `style` (e.g. `sunrise`).

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ChatBackgroundUpdateFailedWebhookEvent: …`

    Complete webhook payload for chat.background_update_failed events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Error details for chat.background_update_failed webhook events.
      See [WebhookErrorCode](#/components/schemas/WebhookErrorCode) for the full error code reference.

      - `chat_id: str`

        Chat identifier (UUID) whose background update failed

      - `error_code: int`

        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.

      - `failed_at: datetime`

        When the failure was detected

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ContactCardReceivedWebhookEvent: …`

    Complete webhook payload for contact_card.received events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      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.

      - `first_name: str`

        First name from the shared contact card

      - `last_name: str`

        Last name from the shared contact card (may be empty)

      - `owner_handle: str`

        Which of your lines they shared it with.

      - `sender_handle: str`

        The person who shared their card — a phone number or email address.

      - `media_url: Optional[str]`

        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.

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: WebhookEventType`

      Valid webhook event types that can be subscribed to.

      **Note:** `message.edited` is only delivered to subscriptions using `webhook_version: "2026-02-03"`.
      Subscribing to this event on a v2025 subscription will not produce any deliveries.

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PhoneNumberStatusUpdatedWebhookEvent: …`

    Complete webhook payload for phone_number.status_updated events

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      Payload for phone_number.status_updated webhook events

      - `changed_at: datetime`

        When the status change occurred

      - `new_reputation: Literal["HEALTHY", "AT_RISK", "CRITICAL"]`

        The new line reputation

        - `"HEALTHY"`

        - `"AT_RISK"`

        - `"CRITICAL"`

      - `new_status: Literal["ACTIVE", "FLAGGED"]`

        The new service status

        - `"ACTIVE"`

        - `"FLAGGED"`

      - `phone_number: str`

        Phone number in E.164 format

      - `previous_reputation: Literal["HEALTHY", "AT_RISK", "CRITICAL"]`

        The previous line reputation

        - `"HEALTHY"`

        - `"AT_RISK"`

        - `"CRITICAL"`

      - `previous_status: Literal["ACTIVE", "FLAGGED"]`

        The previous service status

        - `"ACTIVE"`

        - `"FLAGGED"`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["message.sent", "message.received", "message.read", 43 more]`

      The type of event

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ConnectionCreatedWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      The payment request, as returned by
      `GET /v3/payment_requests/{paymentRequestId}`.

      - `id: str`

        The payment request id.

      - `amount: int`

        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.

      - `checkout_url: str`

        URL the recipient opens to pay
        (`https://zero.linqapp.com/pay/{slug}?session=...`).

      - `created_at: datetime`

      - `currency: str`

      - `object: str`

      - `status: Literal["succeeded", "failed", "canceled", "expired"]`

        - `"succeeded"`

        - `"failed"`

        - `"canceled"`

        - `"expired"`

      - `description: Optional[str]`

      - `discount: Optional[DataDiscount]`

        Subscription mode — the discount Stripe applied, read back
        from the coupon. Absent when none was applied.

        - `coupon: Optional[str]`

        - `label: Optional[str]`

          Name of the coupon/promo code displayed to customers.

        - `promotion_code: Optional[str]`

      - `interval: Optional[Literal["day", "week", "month", "year"]]`

        Subscription mode — how often the subscription renews.

        - `"day"`

        - `"week"`

        - `"month"`

        - `"year"`

      - `interval_count: Optional[int]`

        Subscription mode — intervals per renewal.

      - `metadata: Optional[Dict[str, str]]`

      - `mode: Optional[Literal["payment", "subscription"]]`

        Whether the request collected a one-time charge or started a subscription.

        - `"payment"`

        - `"subscription"`

      - `natural: Optional[DataNatural]`

        Natural-rail join keys, present when `rail: natural`.

        - `payment_request_id: Optional[str]`

          The Natural payment request (`prq_...`).

        - `transaction_id: Optional[str]`

          The settled transaction (`txn_...`).

      - `price_id: Optional[str]`

        Subscription mode — the recurring price subscribed to.

      - `quantity: Optional[int]`

        Subscription mode — units of the price subscribed to.

      - `rail: Optional[Literal["stripe", "natural"]]`

        The rail this request settled on.

        - `"stripe"`

        - `"natural"`

      - `stripe: Optional[DataStripe]`

        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`.

        - `customer_id: Optional[str]`

          The Customer the request is attached to (`cus_...`).
          Always set in subscription mode; set in payment mode
          only when the request was created with a `customer_id`.

        - `payment_intent_id: Optional[str]`

          The PaymentIntent collected at checkout (`pi_...`).

        - `subscription_id: Optional[str]`

          Subscription mode — the Subscription (`sub_...`).

      - `trial_end: Optional[datetime]`

        Subscription mode — when the free trial ends and the first
        charge happens. On a trial request, `payment.succeeded`
        means the payment method was collected ($0 moved).

      - `updated_at: Optional[datetime]`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class ConnectionRevokedWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      The payment request, as returned by
      `GET /v3/payment_requests/{paymentRequestId}`.

      - `id: str`

        The payment request id.

      - `amount: int`

        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.

      - `checkout_url: str`

        URL the recipient opens to pay
        (`https://zero.linqapp.com/pay/{slug}?session=...`).

      - `created_at: datetime`

      - `currency: str`

      - `object: str`

      - `status: Literal["succeeded", "failed", "canceled", "expired"]`

        - `"succeeded"`

        - `"failed"`

        - `"canceled"`

        - `"expired"`

      - `description: Optional[str]`

      - `discount: Optional[DataDiscount]`

        Subscription mode — the discount Stripe applied, read back
        from the coupon. Absent when none was applied.

        - `coupon: Optional[str]`

        - `label: Optional[str]`

          Name of the coupon/promo code displayed to customers.

        - `promotion_code: Optional[str]`

      - `interval: Optional[Literal["day", "week", "month", "year"]]`

        Subscription mode — how often the subscription renews.

        - `"day"`

        - `"week"`

        - `"month"`

        - `"year"`

      - `interval_count: Optional[int]`

        Subscription mode — intervals per renewal.

      - `metadata: Optional[Dict[str, str]]`

      - `mode: Optional[Literal["payment", "subscription"]]`

        Whether the request collected a one-time charge or started a subscription.

        - `"payment"`

        - `"subscription"`

      - `natural: Optional[DataNatural]`

        Natural-rail join keys, present when `rail: natural`.

        - `payment_request_id: Optional[str]`

          The Natural payment request (`prq_...`).

        - `transaction_id: Optional[str]`

          The settled transaction (`txn_...`).

      - `price_id: Optional[str]`

        Subscription mode — the recurring price subscribed to.

      - `quantity: Optional[int]`

        Subscription mode — units of the price subscribed to.

      - `rail: Optional[Literal["stripe", "natural"]]`

        The rail this request settled on.

        - `"stripe"`

        - `"natural"`

      - `stripe: Optional[DataStripe]`

        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`.

        - `customer_id: Optional[str]`

          The Customer the request is attached to (`cus_...`).
          Always set in subscription mode; set in payment mode
          only when the request was created with a `customer_id`.

        - `payment_intent_id: Optional[str]`

          The PaymentIntent collected at checkout (`pi_...`).

        - `subscription_id: Optional[str]`

          Subscription mode — the Subscription (`sub_...`).

      - `trial_end: Optional[datetime]`

        Subscription mode — when the free trial ends and the first
        charge happens. On a trial request, `payment.succeeded`
        means the payment method was collected ($0 moved).

      - `updated_at: Optional[datetime]`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class LocationSharingStartedWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      - `began_at: Optional[datetime]`

        When location sharing started. Always present: falls back to when the share was first observed if the device reported no start time.

      - `chat_id: Optional[str]`

        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.

      - `ends_at: Optional[datetime]`

        When location sharing will expire. Null when sharing indefinitely.

      - `shared_by: str`

        Phone number of the person sharing their location

      - `shared_with: str`

        Your phone number receiving the location

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["location.sharing.started", "message.sent", "message.received", 43 more]`

      - `"location.sharing.started"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.stopped"`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class LocationSharingStoppedWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      - `began_at: Optional[datetime]`

        When the sharing session started, matching began_at on its started event. Always present.

      - `chat_id: Optional[str]`

        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.

      - `ended_at: datetime`

        When the sharing session was observed to stop.

      - `shared_by: str`

        Phone number of the person who stopped sharing

      - `shared_with: str`

        Your phone number that was receiving the location

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["location.sharing.stopped", "message.sent", "message.received", 43 more]`

      - `"location.sharing.stopped"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PaymentAuthorizedWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      The payment request, as returned by
      `GET /v3/payment_requests/{paymentRequestId}`.

      - `id: str`

        The payment request id.

      - `amount: int`

        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.

      - `checkout_url: str`

        URL the recipient opens to pay
        (`https://zero.linqapp.com/pay/{slug}?session=...`).

      - `created_at: datetime`

      - `currency: str`

      - `object: str`

      - `status: Literal["succeeded", "failed", "canceled", "expired"]`

        - `"succeeded"`

        - `"failed"`

        - `"canceled"`

        - `"expired"`

      - `description: Optional[str]`

      - `discount: Optional[DataDiscount]`

        Subscription mode — the discount Stripe applied, read back
        from the coupon. Absent when none was applied.

        - `coupon: Optional[str]`

        - `label: Optional[str]`

          Name of the coupon/promo code displayed to customers.

        - `promotion_code: Optional[str]`

      - `interval: Optional[Literal["day", "week", "month", "year"]]`

        Subscription mode — how often the subscription renews.

        - `"day"`

        - `"week"`

        - `"month"`

        - `"year"`

      - `interval_count: Optional[int]`

        Subscription mode — intervals per renewal.

      - `metadata: Optional[Dict[str, str]]`

      - `mode: Optional[Literal["payment", "subscription"]]`

        Whether the request collected a one-time charge or started a subscription.

        - `"payment"`

        - `"subscription"`

      - `natural: Optional[DataNatural]`

        Natural-rail join keys, present when `rail: natural`.

        - `payment_request_id: Optional[str]`

          The Natural payment request (`prq_...`).

        - `transaction_id: Optional[str]`

          The settled transaction (`txn_...`).

      - `price_id: Optional[str]`

        Subscription mode — the recurring price subscribed to.

      - `quantity: Optional[int]`

        Subscription mode — units of the price subscribed to.

      - `rail: Optional[Literal["stripe", "natural"]]`

        The rail this request settled on.

        - `"stripe"`

        - `"natural"`

      - `stripe: Optional[DataStripe]`

        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`.

        - `customer_id: Optional[str]`

          The Customer the request is attached to (`cus_...`).
          Always set in subscription mode; set in payment mode
          only when the request was created with a `customer_id`.

        - `payment_intent_id: Optional[str]`

          The PaymentIntent collected at checkout (`pi_...`).

        - `subscription_id: Optional[str]`

          Subscription mode — the Subscription (`sub_...`).

      - `trial_end: Optional[datetime]`

        Subscription mode — when the free trial ends and the first
        charge happens. On a trial request, `payment.succeeded`
        means the payment method was collected ($0 moved).

      - `updated_at: Optional[datetime]`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PaymentCanceledWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      The payment request, as returned by
      `GET /v3/payment_requests/{paymentRequestId}`.

      - `id: str`

        The payment request id.

      - `amount: int`

        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.

      - `checkout_url: str`

        URL the recipient opens to pay
        (`https://zero.linqapp.com/pay/{slug}?session=...`).

      - `created_at: datetime`

      - `currency: str`

      - `object: str`

      - `status: Literal["succeeded", "failed", "canceled", "expired"]`

        - `"succeeded"`

        - `"failed"`

        - `"canceled"`

        - `"expired"`

      - `description: Optional[str]`

      - `discount: Optional[DataDiscount]`

        Subscription mode — the discount Stripe applied, read back
        from the coupon. Absent when none was applied.

        - `coupon: Optional[str]`

        - `label: Optional[str]`

          Name of the coupon/promo code displayed to customers.

        - `promotion_code: Optional[str]`

      - `interval: Optional[Literal["day", "week", "month", "year"]]`

        Subscription mode — how often the subscription renews.

        - `"day"`

        - `"week"`

        - `"month"`

        - `"year"`

      - `interval_count: Optional[int]`

        Subscription mode — intervals per renewal.

      - `metadata: Optional[Dict[str, str]]`

      - `mode: Optional[Literal["payment", "subscription"]]`

        Whether the request collected a one-time charge or started a subscription.

        - `"payment"`

        - `"subscription"`

      - `natural: Optional[DataNatural]`

        Natural-rail join keys, present when `rail: natural`.

        - `payment_request_id: Optional[str]`

          The Natural payment request (`prq_...`).

        - `transaction_id: Optional[str]`

          The settled transaction (`txn_...`).

      - `price_id: Optional[str]`

        Subscription mode — the recurring price subscribed to.

      - `quantity: Optional[int]`

        Subscription mode — units of the price subscribed to.

      - `rail: Optional[Literal["stripe", "natural"]]`

        The rail this request settled on.

        - `"stripe"`

        - `"natural"`

      - `stripe: Optional[DataStripe]`

        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`.

        - `customer_id: Optional[str]`

          The Customer the request is attached to (`cus_...`).
          Always set in subscription mode; set in payment mode
          only when the request was created with a `customer_id`.

        - `payment_intent_id: Optional[str]`

          The PaymentIntent collected at checkout (`pi_...`).

        - `subscription_id: Optional[str]`

          Subscription mode — the Subscription (`sub_...`).

      - `trial_end: Optional[datetime]`

        Subscription mode — when the free trial ends and the first
        charge happens. On a trial request, `payment.succeeded`
        means the payment method was collected ($0 moved).

      - `updated_at: Optional[datetime]`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PaymentDeclinedWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      The payment request, as returned by
      `GET /v3/payment_requests/{paymentRequestId}`.

      - `id: str`

        The payment request id.

      - `amount: int`

        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.

      - `checkout_url: str`

        URL the recipient opens to pay
        (`https://zero.linqapp.com/pay/{slug}?session=...`).

      - `created_at: datetime`

      - `currency: str`

      - `object: str`

      - `status: Literal["succeeded", "failed", "canceled", "expired"]`

        - `"succeeded"`

        - `"failed"`

        - `"canceled"`

        - `"expired"`

      - `description: Optional[str]`

      - `discount: Optional[DataDiscount]`

        Subscription mode — the discount Stripe applied, read back
        from the coupon. Absent when none was applied.

        - `coupon: Optional[str]`

        - `label: Optional[str]`

          Name of the coupon/promo code displayed to customers.

        - `promotion_code: Optional[str]`

      - `interval: Optional[Literal["day", "week", "month", "year"]]`

        Subscription mode — how often the subscription renews.

        - `"day"`

        - `"week"`

        - `"month"`

        - `"year"`

      - `interval_count: Optional[int]`

        Subscription mode — intervals per renewal.

      - `metadata: Optional[Dict[str, str]]`

      - `mode: Optional[Literal["payment", "subscription"]]`

        Whether the request collected a one-time charge or started a subscription.

        - `"payment"`

        - `"subscription"`

      - `natural: Optional[DataNatural]`

        Natural-rail join keys, present when `rail: natural`.

        - `payment_request_id: Optional[str]`

          The Natural payment request (`prq_...`).

        - `transaction_id: Optional[str]`

          The settled transaction (`txn_...`).

      - `price_id: Optional[str]`

        Subscription mode — the recurring price subscribed to.

      - `quantity: Optional[int]`

        Subscription mode — units of the price subscribed to.

      - `rail: Optional[Literal["stripe", "natural"]]`

        The rail this request settled on.

        - `"stripe"`

        - `"natural"`

      - `stripe: Optional[DataStripe]`

        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`.

        - `customer_id: Optional[str]`

          The Customer the request is attached to (`cus_...`).
          Always set in subscription mode; set in payment mode
          only when the request was created with a `customer_id`.

        - `payment_intent_id: Optional[str]`

          The PaymentIntent collected at checkout (`pi_...`).

        - `subscription_id: Optional[str]`

          Subscription mode — the Subscription (`sub_...`).

      - `trial_end: Optional[datetime]`

        Subscription mode — when the free trial ends and the first
        charge happens. On a trial request, `payment.succeeded`
        means the payment method was collected ($0 moved).

      - `updated_at: Optional[datetime]`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PaymentExpiredWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      The payment request, as returned by
      `GET /v3/payment_requests/{paymentRequestId}`.

      - `id: str`

        The payment request id.

      - `amount: int`

        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.

      - `checkout_url: str`

        URL the recipient opens to pay
        (`https://zero.linqapp.com/pay/{slug}?session=...`).

      - `created_at: datetime`

      - `currency: str`

      - `object: str`

      - `status: Literal["succeeded", "failed", "canceled", "expired"]`

        - `"succeeded"`

        - `"failed"`

        - `"canceled"`

        - `"expired"`

      - `description: Optional[str]`

      - `discount: Optional[DataDiscount]`

        Subscription mode — the discount Stripe applied, read back
        from the coupon. Absent when none was applied.

        - `coupon: Optional[str]`

        - `label: Optional[str]`

          Name of the coupon/promo code displayed to customers.

        - `promotion_code: Optional[str]`

      - `interval: Optional[Literal["day", "week", "month", "year"]]`

        Subscription mode — how often the subscription renews.

        - `"day"`

        - `"week"`

        - `"month"`

        - `"year"`

      - `interval_count: Optional[int]`

        Subscription mode — intervals per renewal.

      - `metadata: Optional[Dict[str, str]]`

      - `mode: Optional[Literal["payment", "subscription"]]`

        Whether the request collected a one-time charge or started a subscription.

        - `"payment"`

        - `"subscription"`

      - `natural: Optional[DataNatural]`

        Natural-rail join keys, present when `rail: natural`.

        - `payment_request_id: Optional[str]`

          The Natural payment request (`prq_...`).

        - `transaction_id: Optional[str]`

          The settled transaction (`txn_...`).

      - `price_id: Optional[str]`

        Subscription mode — the recurring price subscribed to.

      - `quantity: Optional[int]`

        Subscription mode — units of the price subscribed to.

      - `rail: Optional[Literal["stripe", "natural"]]`

        The rail this request settled on.

        - `"stripe"`

        - `"natural"`

      - `stripe: Optional[DataStripe]`

        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`.

        - `customer_id: Optional[str]`

          The Customer the request is attached to (`cus_...`).
          Always set in subscription mode; set in payment mode
          only when the request was created with a `customer_id`.

        - `payment_intent_id: Optional[str]`

          The PaymentIntent collected at checkout (`pi_...`).

        - `subscription_id: Optional[str]`

          Subscription mode — the Subscription (`sub_...`).

      - `trial_end: Optional[datetime]`

        Subscription mode — when the free trial ends and the first
        charge happens. On a trial request, `payment.succeeded`
        means the payment method was collected ($0 moved).

      - `updated_at: Optional[datetime]`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.

  - `class PaymentSucceededWebhookEvent: …`

    - `api_version: str`

      API version for the webhook payload format

    - `created_at: datetime`

      When the event was created

    - `data: Data`

      The payment request, as returned by
      `GET /v3/payment_requests/{paymentRequestId}`.

      - `id: str`

        The payment request id.

      - `amount: int`

        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.

      - `checkout_url: str`

        URL the recipient opens to pay
        (`https://zero.linqapp.com/pay/{slug}?session=...`).

      - `created_at: datetime`

      - `currency: str`

      - `object: str`

      - `status: Literal["succeeded", "failed", "canceled", "expired"]`

        - `"succeeded"`

        - `"failed"`

        - `"canceled"`

        - `"expired"`

      - `description: Optional[str]`

      - `discount: Optional[DataDiscount]`

        Subscription mode — the discount Stripe applied, read back
        from the coupon. Absent when none was applied.

        - `coupon: Optional[str]`

        - `label: Optional[str]`

          Name of the coupon/promo code displayed to customers.

        - `promotion_code: Optional[str]`

      - `interval: Optional[Literal["day", "week", "month", "year"]]`

        Subscription mode — how often the subscription renews.

        - `"day"`

        - `"week"`

        - `"month"`

        - `"year"`

      - `interval_count: Optional[int]`

        Subscription mode — intervals per renewal.

      - `metadata: Optional[Dict[str, str]]`

      - `mode: Optional[Literal["payment", "subscription"]]`

        Whether the request collected a one-time charge or started a subscription.

        - `"payment"`

        - `"subscription"`

      - `natural: Optional[DataNatural]`

        Natural-rail join keys, present when `rail: natural`.

        - `payment_request_id: Optional[str]`

          The Natural payment request (`prq_...`).

        - `transaction_id: Optional[str]`

          The settled transaction (`txn_...`).

      - `price_id: Optional[str]`

        Subscription mode — the recurring price subscribed to.

      - `quantity: Optional[int]`

        Subscription mode — units of the price subscribed to.

      - `rail: Optional[Literal["stripe", "natural"]]`

        The rail this request settled on.

        - `"stripe"`

        - `"natural"`

      - `stripe: Optional[DataStripe]`

        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`.

        - `customer_id: Optional[str]`

          The Customer the request is attached to (`cus_...`).
          Always set in subscription mode; set in payment mode
          only when the request was created with a `customer_id`.

        - `payment_intent_id: Optional[str]`

          The PaymentIntent collected at checkout (`pi_...`).

        - `subscription_id: Optional[str]`

          Subscription mode — the Subscription (`sub_...`).

      - `trial_end: Optional[datetime]`

        Subscription mode — when the free trial ends and the first
        charge happens. On a trial request, `payment.succeeded`
        means the payment method was collected ($0 moved).

      - `updated_at: Optional[datetime]`

    - `event_id: str`

      Unique identifier for this event (for deduplication)

    - `event_type: Literal["payment.succeeded", "payment.canceled", "payment.expired", 43 more]`

      - `"payment.succeeded"`

      - `"payment.canceled"`

      - `"payment.expired"`

      - `"message.sent"`

      - `"message.received"`

      - `"message.read"`

      - `"message.delivered"`

      - `"message.failed"`

      - `"message.edited"`

      - `"reaction.added"`

      - `"reaction.removed"`

      - `"poll.received"`

      - `"poll.failed"`

      - `"poll.sent"`

      - `"poll.delivered"`

      - `"poll.read"`

      - `"poll.updated"`

      - `"poll.vote.added"`

      - `"poll.vote.removed"`

      - `"poll.reaction.added"`

      - `"participant.added"`

      - `"participant.removed"`

      - `"chat.created"`

      - `"chat.group_name_updated"`

      - `"chat.group_icon_updated"`

      - `"chat.group_name_update_failed"`

      - `"chat.group_icon_update_failed"`

      - `"chat.background_updated"`

      - `"chat.background_update_failed"`

      - `"chat.typing_indicator.started"`

      - `"chat.typing_indicator.stopped"`

      - `"phone_number.status_updated"`

      - `"contact_card.received"`

      - `"call.initiated"`

      - `"call.ringing"`

      - `"call.answered"`

      - `"call.ended"`

      - `"call.failed"`

      - `"call.declined"`

      - `"call.no_answer"`

      - `"location.sharing.started"`

      - `"location.sharing.stopped"`

      - `"payment.declined"`

      - `"payment.authorized"`

      - `"connection.created"`

      - `"connection.revoked"`

    - `partner_id: str`

      Partner identifier. Present on all webhooks for cross-referencing.

    - `trace_id: str`

      Trace ID for debugging and correlation across systems.

    - `webhook_version: str`

      Date-based webhook payload version.
      Determined by the `?version=` query parameter in your webhook subscription URL.
      If no version parameter is specified, defaults based on subscription creation date.
