# Messages

## Send a message (auto-selected from-number)

`client.Messages.New(ctx, params) (*MessageNewResponse, error)`

**post** `/v3/messages`

Send a message to one or more recipients **without supplying a `from`
number**. Linq resolves both the sending line and the target chat for you,
then returns exactly which line was used, which chat the message landed in,
whether a new chat was created, and every resulting message id.

This fuses "create chat" and "send message" behind a single
message-centric resource. Provide only the recipients (`to`) and the
`message`; the platform decides the rest.

## How the from-number and chat are chosen

- **Reuse** — if a chat with exactly these recipients already exists on a
  line that can still send, the message is sent into that chat on its
  existing line (`from_selection.reason = reused_active_chat`). The
  most-recently-active such chat wins; chats stranded on flagged lines
  (e.g. by an earlier failover) are skipped.
- **New** — if no such chat exists, a new chat is created on the best
  available line (`from_selection.reason = new_best_number`).
- **Failover** — if matching chats exist but none is on a line that can
  send, a **new** chat is created on a fresh best line and the flagged chat
  is abandoned (`from_selection.reason = failover_flagged`,
  `previous_chat_id` set). If you supply `continuation_message`, that
  text is sent as the single message INSTEAD of `message` (useful as a
  fresh-number-appropriate opener). Exactly one message is sent either way.

Recipients (`to`) are an order-independent set: a single handle is a direct
chat, multiple handles a group chat.

## Excluding lines

`exclude_from` keeps specific lines out of **this** send's line pick. It
only affects picking a line for a new chat — an existing chat is always
reused on its own line, preferring a chat on a non-excluded line when the
recipients have more than one. An exclusion never abandons a live chat or
moves it to a new number, so if the only chat these recipients have is on
an excluded line, that chat is still used. `from` tells you the line that
was actually used.

## Differences from POST /v3/chats

- The first message **may contain a link** (including for a newly created
  chat). Note: sending a link as the very first message on a freshly
  selected line can elevate that line's flagging risk — it is allowed, not
  recommended.
- Voice memos are **not** supported here. To send an iMessage voice-memo
  bubble, use `POST /v3/chats/{chatId}/voicememo` with a known chat id.

## Service preference, effects, decorations

Set `message.preferred_service` (`iMessage` | `RCS` | `SMS`), `message.effect`,
and per-part `text_decorations` exactly as on the other send endpoints.

Always responds `202 Accepted` — chat creation is incidental to the send.

### Parameters

- `params MessageNewParams`

  - `Message param.Field[MessageContent]`

    Body param: Message content container. Groups all message-related fields together,
    separating the "what" (message content) from the "where" (routing fields like from/to).

    A message carries EITHER `parts` — text and attachments, which compose
    into one bubble — or a single `experience` invocation, which renders an
    experience inside Linq's iMessage app. Never both: an app card is the whole message
    (Apple's `MSMessage` cannot coexist with text), so copy and a card are
    two sends, not one.

  - `To param.Field[[]string]`

    Body param: Recipient handles (E.164 phone numbers or email addresses). One handle
    is a direct chat; multiple handles a group chat. Order-independent — the
    set identifies the chat.

  - `ContinuationMessage param.Field[MessageNewParamsContinuationMessage]`

    Body param: Text-only fallback that **replaces** `message` ONLY on the failover branch —
    when a chat with these recipients already existed but its line was flagged,
    so a new chat is created on a fresh line. On that branch this text is sent as
    the single message instead of `message` (the recipient is on a new number, so
    you typically want a fresh-number-appropriate opener rather than the original
    content). Ignored otherwise (a healthy reuse, or genuine first contact).
    Carries no parts, media, or effects — exactly one message is ever sent.

    - `Text string`

      The replacement message text, sent as the single message on failover.

  - `ExcludeFrom param.Field[[]string]`

    Body param: Lines (E.164) not to pick for this send. Applies for this request
    only — nothing is remembered between calls.

    **Exclusion only affects picking a line for a new chat.** If `to`
    already has a chat, that chat is reused on its own line, and a chat on
    a non-excluded line is preferred when there is more than one. If the
    only chat these recipients have is on an excluded line, it is still
    reused — an exclusion never abandons a live chat or moves it to a new
    number. Check `from` in the response to see the line that was actually
    used.

    Numbers that are not your lines are ignored. Every entry must be
    E.164 — a value like `4155551234` is rejected rather than silently
    skipped. Excluding every one of your available lines returns 400 when
    a line has to be picked.

  - `OverrideOptout param.Field[bool]`

    Body param: Send even though the recipient asked you to stop (`403`, error code
    `2024`). Applies to this request only: the opt-out stays in place, so
    the next send without this flag is rejected again. Every override is
    recorded against your API key.

  - `IdempotencyKey param.Field[string]`

    Header param: Optional idempotency key for the send. Reuse the same key to safely
    retry without sending twice. May also be supplied as
    `message.idempotency_key`.

### Returns

- `type MessageNewResponse struct{…}`

  Result of an auto-from send. Self-describing: which line was used, which
  chat the message landed in, whether a new chat was created, and the
  resulting message id(s).

  - `ChatID string`

    The resolved chat (reused or newly created) the message landed in.

  - `CreatedNewChat bool`

    True when a new chat was created (new or failover), false on reuse.

  - `From string`

    The line (E.164) the message was actually sent from.

  - `FromSelection MessageNewResponseFromSelection`

    Why this line/chat was chosen.

    - `Reason string`

      - `reused_active_chat` — reused an existing chat on its healthy line
      - `new_best_number` — created a new chat on the best available line
      - `failover_flagged` — no existing chat for these recipients was on
        a line that could send; created a new chat on a fresh line

      - `const MessageNewResponseFromSelectionReasonReusedActiveChat MessageNewResponseFromSelectionReason = "reused_active_chat"`

      - `const MessageNewResponseFromSelectionReasonNewBestNumber MessageNewResponseFromSelectionReason = "new_best_number"`

      - `const MessageNewResponseFromSelectionReasonFailoverFlagged MessageNewResponseFromSelectionReason = "failover_flagged"`

    - `ReusedExistingChat bool`

      True only when an existing chat was reused.

  - `Handles []ChatHandle`

    Participants of the resolved chat.

    - `ID string`

      Unique identifier for this handle

    - `Handle string`

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

    - `JoinedAt Time`

      When this participant joined the chat

    - `Service ServiceType`

      Messaging service type

      - `const ServiceTypeIMessage ServiceType = "iMessage"`

      - `const ServiceTypeSMS ServiceType = "SMS"`

      - `const ServiceTypeRCS ServiceType = "RCS"`

    - `IsMe bool`

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

    - `LeftAt Time`

      When they left (if applicable)

    - `Status ChatHandleStatus`

      Participant status

      - `const ChatHandleStatusActive ChatHandleStatus = "active"`

      - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

      - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

  - `IsGroup bool`

    Whether the resolved chat is a group chat.

  - `Message SentMessage`

    A message that was sent (used in CreateChat and SendMessage responses)

    - `ID string`

      Message identifier (UUID)

    - `CreatedAt Time`

      When the message was created

    - `DeliveryStatus SentMessageDeliveryStatus`

      Current delivery status of a message

      - `const SentMessageDeliveryStatusPending SentMessageDeliveryStatus = "pending"`

      - `const SentMessageDeliveryStatusQueued SentMessageDeliveryStatus = "queued"`

      - `const SentMessageDeliveryStatusSent SentMessageDeliveryStatus = "sent"`

      - `const SentMessageDeliveryStatusDelivered SentMessageDeliveryStatus = "delivered"`

      - `const SentMessageDeliveryStatusReceived SentMessageDeliveryStatus = "received"`

      - `const SentMessageDeliveryStatusRead SentMessageDeliveryStatus = "read"`

      - `const SentMessageDeliveryStatusFailed SentMessageDeliveryStatus = "failed"`

    - `IsRead bool`

      DEPRECATED: Use `delivery_status == "read"` instead. Whether the message has been read.

    - `Parts []SentMessagePartUnion`

      Message parts in order (text, media, and link)

      - `type TextPartResponse struct{…}`

        A text message part

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

            - `ID string`

              Unique identifier for this handle

            - `Handle string`

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

            - `JoinedAt Time`

              When this participant joined the chat

            - `Service ServiceType`

              Messaging service type

            - `IsMe bool`

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

            - `LeftAt Time`

              When they left (if applicable)

            - `Status ChatHandleStatus`

              Participant status

          - `IsMe bool`

            Whether this reaction is from the current user

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

            - `const ReactionTypeLove ReactionType = "love"`

            - `const ReactionTypeLike ReactionType = "like"`

            - `const ReactionTypeDislike ReactionType = "dislike"`

            - `const ReactionTypeLaugh ReactionType = "laugh"`

            - `const ReactionTypeEmphasize ReactionType = "emphasize"`

            - `const ReactionTypeQuestion ReactionType = "question"`

            - `const ReactionTypeCustom ReactionType = "custom"`

            - `const ReactionTypeSticker ReactionType = "sticker"`

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

            - `FileName string`

              Filename of the sticker

            - `Height int64`

              Sticker image height in pixels

            - `MimeType string`

              MIME type of the sticker image

            - `URL string`

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

            - `Width int64`

              Sticker image width in pixels

        - `Type TextPartResponseType`

          Indicates this is a text message part

          - `const TextPartResponseTypeText TextPartResponseType = "text"`

        - `Value string`

          The text content

        - `Mention string`

          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.

        - `MentionRange []int64`

          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 []TextPartResponseMention`

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

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

          - `IsMe bool`

            Whether the mentioned participant is this line.

          - `Range []int64`

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

        - `TextDecorations []TextDecoration`

          Text decorations applied to character ranges in the value

          - `Range []int64`

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

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

            - `const TextDecorationAnimationBig TextDecorationAnimation = "big"`

            - `const TextDecorationAnimationSmall TextDecorationAnimation = "small"`

            - `const TextDecorationAnimationShake TextDecorationAnimation = "shake"`

            - `const TextDecorationAnimationNod TextDecorationAnimation = "nod"`

            - `const TextDecorationAnimationExplode TextDecorationAnimation = "explode"`

            - `const TextDecorationAnimationRipple TextDecorationAnimation = "ripple"`

            - `const TextDecorationAnimationBloom TextDecorationAnimation = "bloom"`

            - `const TextDecorationAnimationJitter TextDecorationAnimation = "jitter"`

          - `Style TextDecorationStyle`

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

            - `const TextDecorationStyleBold TextDecorationStyle = "bold"`

            - `const TextDecorationStyleItalic TextDecorationStyle = "italic"`

            - `const TextDecorationStyleStrikethrough TextDecorationStyle = "strikethrough"`

            - `const TextDecorationStyleUnderline TextDecorationStyle = "underline"`

      - `type MediaPartResponse struct{…}`

        A media attachment part

        - `ID string`

          Unique attachment identifier

        - `Filename string`

          Original filename

        - `MimeType string`

          MIME type of the file

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `SizeBytes int64`

          File size in bytes

        - `Type MediaPartResponseType`

          Indicates this is a media attachment part

          - `const MediaPartResponseTypeMedia MediaPartResponseType = "media"`

        - `URL string`

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

      - `type LinkPartResponse struct{…}`

        A rich link preview part

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `Type LinkPartResponseType`

          Indicates this is a rich link preview part

          - `const LinkPartResponseTypeLink LinkPartResponseType = "link"`

        - `Value string`

          The URL

      - `type SentMessagePartIMessageAppPartResponse struct{…}`

        An iMessage app card part.

        - `App SentMessagePartIMessageAppPartResponseApp`

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

          - `BundleID string`

            Bundle identifier of the Messages app extension. Must not contain `:`.

          - `Name string`

            Display name of the app, shown by Messages' fallback UI.

          - `TeamID string`

            The app's 10-character uppercase alphanumeric team identifier.

          - `AppStoreID int64`

            The owning app's App Store id (optional). When set, recipients without the iMessage app
            installed see a "Get the app" affordance.

        - `Layout SentMessagePartIMessageAppPartResponseLayout`

          Visible layout of the card. At least one of
          `caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be
          set, otherwise the card renders as an empty bubble.

          `image_url` displays a preview image at the top of the card. The image renders on the
          recipient's card whether or not they have your app installed. The small icon beside the
          caption is the app's own icon and is not settable here.

          `* Note - requires a trusted chat w/ inbound activity`

          `image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle
          beneath it). They only appear when `image_url` is set — without an image there is nothing to
          overlay — so setting either without `image_url` is rejected.

          - `Caption string`

            Primary label, top-left and bold.

          - `ImageSubtitle string`

            Text shown below `image_title`, overlaid on the card image. Requires `image_url`.

          - `ImageTitle string`

            Bold text overlaid on the card image. Requires `image_url` (rejected without it).

          - `ImageURL string`

            URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.

          - `Subcaption string`

            Secondary label, below `caption` on the left.

          - `TrailingCaption string`

            Label shown top-right.

          - `TrailingSubcaption string`

            Label shown below `trailing_caption`, on the right.

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `Type string`

          Indicates this is an iMessage app card part.

          - `const SentMessagePartIMessageAppPartResponseTypeIMessageApp SentMessagePartIMessageAppPartResponseType = "imessage_app"`

        - `URL string`

          The URL delivered to the iMessage app on tap.

        - `FallbackText string`

          Fallback text for surfaces that cannot render the card.

      - `type SentMessagePartAppClipPartResponse struct{…}`

        An App Clip card part

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `Type string`

          Indicates this is an App Clip card part

          - `const SentMessagePartAppClipPartResponseTypeAppClip SentMessagePartAppClipPartResponseType = "app_clip"`

        - `Value string`

          The App Clip link the card opens

        - `Description string`

          The card's summary line, composed by Linq from the App Clip page

        - `ImageURL string`

          The card's preview image

        - `Title string`

          The card's headline, composed by Linq from the App Clip page

    - `SentAt Time`

      When the message was actually sent (null if still queued)

    - `DeliveredAt Time`

      When the message was delivered

    - `Effect MessageEffect`

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

      - `Name string`

        Name of the effect. Common values:

        - Screen effects: confetti, fireworks, lasers, sparkles, celebration, hearts, love, balloons, happy_birthday, echo, spotlight
        - Bubble effects: slam, loud, gentle, invisible

      - `Type MessageEffectType`

        Type of effect

        - `const MessageEffectTypeScreen MessageEffectType = "screen"`

        - `const MessageEffectTypeBubble MessageEffectType = "bubble"`

    - `FromHandle ChatHandle`

      The sender of this message as a full handle object

    - `PreferredService ServiceType`

      Messaging service type

    - `ReplyTo ReplyTo`

      Indicates this message is a threaded reply to another message

      - `MessageID string`

        The ID of the message to reply to

      - `PartIndex int64`

        The specific message part to reply to (0-based index).
        Defaults to 0 (first part) if not provided.
        Use this when replying to a specific part of a multipart message.

    - `Service ServiceType`

      Messaging service type

  - `Service ServiceType`

    Messaging service type

  - `PreviousChatID string`

    Set ONLY on `failover_flagged`: the abandoned flagged chat that was NOT
    sent into. Null otherwise.

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  message, err := client.Messages.New(context.TODO(), linqgo.MessageNewParams{
    Message: linqgo.MessageContentParam{
      Parts: []linqgo.MessageContentPartUnionParam{linqgo.MessageContentPartUnionParam{
        OfText: &linqgo.TextPartParam{
          Type: linqgo.TextPartTypeText,
          Value: "Hi! Thanks for reaching out — how can we help?",
        },
      }},
    },
    To: []string{"+14155559876"},
  })
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", message.ChatID)
}
```

#### Response

```json
{
  "chat_id": "94c6bf33-31d9-40e3-a0e9-f94250ecedb9",
  "created_new_chat": false,
  "from": "+12052535597",
  "from_selection": {
    "reason": "reused_active_chat",
    "reused_existing_chat": true
  },
  "handles": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "handle": "+15551234567",
      "joined_at": "2025-05-21T15:30:00.000-05:00",
      "service": "iMessage",
      "is_me": false,
      "left_at": "2019-12-27T18:11:19.117Z",
      "status": "active"
    }
  ],
  "is_group": false,
  "message": {
    "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    "created_at": "2025-10-23T13:07:55.019-05:00",
    "delivery_status": "pending",
    "is_read": false,
    "parts": [
      {
        "reactions": [
          {
            "handle": {
              "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
              "handle": "+15551234567",
              "joined_at": "2025-05-21T15:30:00.000-05:00",
              "service": "iMessage",
              "is_me": false,
              "left_at": "2019-12-27T18:11:19.117Z",
              "status": "active"
            },
            "is_me": false,
            "type": "love",
            "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
            "custom_emoji": null,
            "sticker": {
              "file_name": "sticker.png",
              "height": 420,
              "mime_type": "image/png",
              "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
              "width": 420
            }
          }
        ],
        "type": "text",
        "value": "Hello!",
        "mention": "+14155551234",
        "mention_range": [
          4,
          9
        ],
        "mentions": [
          {
            "handle": "+14155550123",
            "is_me": true,
            "range": [
              4,
              9
            ]
          }
        ],
        "text_decorations": [
          {
            "range": [
              0,
              5
            ],
            "animation": "shake",
            "style": "bold"
          }
        ]
      }
    ],
    "sent_at": null,
    "delivered_at": null,
    "effect": {
      "name": "confetti",
      "type": "screen"
    },
    "from_handle": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "handle": "+15551234567",
      "joined_at": "2025-05-21T15:30:00.000-05:00",
      "service": "iMessage",
      "is_me": false,
      "left_at": "2019-12-27T18:11:19.117Z",
      "status": "active"
    },
    "preferred_service": "iMessage",
    "reply_to": {
      "message_id": "550e8400-e29b-41d4-a716-446655440000",
      "part_index": 0
    },
    "service": "iMessage"
  },
  "service": "iMessage",
  "previous_chat_id": null
}
```

## Get all messages in a thread

`client.Messages.ListMessagesThread(ctx, messageID, query) (*ListMessagesPagination[Message], error)`

**get** `/v3/messages/{messageId}/thread`

Retrieve all messages in a conversation thread. Given any message ID in the thread,
returns the originator message and all replies in chronological order.

If the message is not part of a thread, returns just that single message.

Supports pagination and configurable ordering.

### Parameters

- `messageID string`

- `query MessageListMessagesThreadParams`

  - `Cursor param.Field[string]`

    Pagination cursor from previous next_cursor response

  - `Limit param.Field[int64]`

    Maximum number of messages to return

  - `Order param.Field[MessageListMessagesThreadParamsOrder]`

    Sort order for messages (asc = oldest first, desc = newest first)

    - `const MessageListMessagesThreadParamsOrderAsc MessageListMessagesThreadParamsOrder = "asc"`

    - `const MessageListMessagesThreadParamsOrderDesc MessageListMessagesThreadParamsOrder = "desc"`

### Returns

- `type Message struct{…}`

  - `ID string`

    Unique identifier for the message

  - `ChatID string`

    ID of the chat this message belongs to

  - `CreatedAt Time`

    When the message was created

  - `DeliveryStatus MessageDeliveryStatus`

    Current delivery status of a message

    - `const MessageDeliveryStatusPending MessageDeliveryStatus = "pending"`

    - `const MessageDeliveryStatusQueued MessageDeliveryStatus = "queued"`

    - `const MessageDeliveryStatusSent MessageDeliveryStatus = "sent"`

    - `const MessageDeliveryStatusDelivered MessageDeliveryStatus = "delivered"`

    - `const MessageDeliveryStatusReceived MessageDeliveryStatus = "received"`

    - `const MessageDeliveryStatusRead MessageDeliveryStatus = "read"`

    - `const MessageDeliveryStatusFailed MessageDeliveryStatus = "failed"`

  - `IsDelivered bool`

    DEPRECATED: Use `delivery_status` instead (true when `delivery_status` is `delivered` or `read`). Whether the message has been delivered.

  - `IsFromMe bool`

    Whether this message was sent by the authenticated user

  - `IsRead bool`

    DEPRECATED: Use `delivery_status == "read"` instead. Whether the message has been read.

  - `UpdatedAt Time`

    When the message was last updated

  - `DeliveredAt Time`

    When the message was delivered

  - `Effect MessageEffect`

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

    - `Name string`

      Name of the effect. Common values:

      - Screen effects: confetti, fireworks, lasers, sparkles, celebration, hearts, love, balloons, happy_birthday, echo, spotlight
      - Bubble effects: slam, loud, gentle, invisible

    - `Type MessageEffectType`

      Type of effect

      - `const MessageEffectTypeScreen MessageEffectType = "screen"`

      - `const MessageEffectTypeBubble MessageEffectType = "bubble"`

  - `From string`

    DEPRECATED: Use from_handle instead. Phone number of the message sender.

  - `FromHandle ChatHandle`

    The sender of this message as a full handle object

    - `ID string`

      Unique identifier for this handle

    - `Handle string`

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

    - `JoinedAt Time`

      When this participant joined the chat

    - `Service ServiceType`

      Messaging service type

      - `const ServiceTypeIMessage ServiceType = "iMessage"`

      - `const ServiceTypeSMS ServiceType = "SMS"`

      - `const ServiceTypeRCS ServiceType = "RCS"`

    - `IsMe bool`

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

    - `LeftAt Time`

      When they left (if applicable)

    - `Status ChatHandleStatus`

      Participant status

      - `const ChatHandleStatusActive ChatHandleStatus = "active"`

      - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

      - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

  - `Parts []MessagePartUnion`

    Message parts in order (text, media, and link)

    - `type TextPartResponse struct{…}`

      A text message part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

          - `const ReactionTypeLove ReactionType = "love"`

          - `const ReactionTypeLike ReactionType = "like"`

          - `const ReactionTypeDislike ReactionType = "dislike"`

          - `const ReactionTypeLaugh ReactionType = "laugh"`

          - `const ReactionTypeEmphasize ReactionType = "emphasize"`

          - `const ReactionTypeQuestion ReactionType = "question"`

          - `const ReactionTypeCustom ReactionType = "custom"`

          - `const ReactionTypeSticker ReactionType = "sticker"`

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

          - `FileName string`

            Filename of the sticker

          - `Height int64`

            Sticker image height in pixels

          - `MimeType string`

            MIME type of the sticker image

          - `URL string`

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

          - `Width int64`

            Sticker image width in pixels

      - `Type TextPartResponseType`

        Indicates this is a text message part

        - `const TextPartResponseTypeText TextPartResponseType = "text"`

      - `Value string`

        The text content

      - `Mention string`

        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.

      - `MentionRange []int64`

        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 []TextPartResponseMention`

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

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

        - `IsMe bool`

          Whether the mentioned participant is this line.

        - `Range []int64`

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

      - `TextDecorations []TextDecoration`

        Text decorations applied to character ranges in the value

        - `Range []int64`

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

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

          - `const TextDecorationAnimationBig TextDecorationAnimation = "big"`

          - `const TextDecorationAnimationSmall TextDecorationAnimation = "small"`

          - `const TextDecorationAnimationShake TextDecorationAnimation = "shake"`

          - `const TextDecorationAnimationNod TextDecorationAnimation = "nod"`

          - `const TextDecorationAnimationExplode TextDecorationAnimation = "explode"`

          - `const TextDecorationAnimationRipple TextDecorationAnimation = "ripple"`

          - `const TextDecorationAnimationBloom TextDecorationAnimation = "bloom"`

          - `const TextDecorationAnimationJitter TextDecorationAnimation = "jitter"`

        - `Style TextDecorationStyle`

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

          - `const TextDecorationStyleBold TextDecorationStyle = "bold"`

          - `const TextDecorationStyleItalic TextDecorationStyle = "italic"`

          - `const TextDecorationStyleStrikethrough TextDecorationStyle = "strikethrough"`

          - `const TextDecorationStyleUnderline TextDecorationStyle = "underline"`

    - `type MediaPartResponse struct{…}`

      A media attachment part

      - `ID string`

        Unique attachment identifier

      - `Filename string`

        Original filename

      - `MimeType string`

        MIME type of the file

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `SizeBytes int64`

        File size in bytes

      - `Type MediaPartResponseType`

        Indicates this is a media attachment part

        - `const MediaPartResponseTypeMedia MediaPartResponseType = "media"`

      - `URL string`

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

    - `type LinkPartResponse struct{…}`

      A rich link preview part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type LinkPartResponseType`

        Indicates this is a rich link preview part

        - `const LinkPartResponseTypeLink LinkPartResponseType = "link"`

      - `Value string`

        The URL

    - `type MessagePartIMessageAppPartResponse struct{…}`

      An iMessage app card part.

      - `App MessagePartIMessageAppPartResponseApp`

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

        - `BundleID string`

          Bundle identifier of the Messages app extension. Must not contain `:`.

        - `Name string`

          Display name of the app, shown by Messages' fallback UI.

        - `TeamID string`

          The app's 10-character uppercase alphanumeric team identifier.

        - `AppStoreID int64`

          The owning app's App Store id (optional). When set, recipients without the iMessage app
          installed see a "Get the app" affordance.

      - `Layout MessagePartIMessageAppPartResponseLayout`

        Visible layout of the card. At least one of
        `caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be
        set, otherwise the card renders as an empty bubble.

        `image_url` displays a preview image at the top of the card. The image renders on the
        recipient's card whether or not they have your app installed. The small icon beside the
        caption is the app's own icon and is not settable here.

        `* Note - requires a trusted chat w/ inbound activity`

        `image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle
        beneath it). They only appear when `image_url` is set — without an image there is nothing to
        overlay — so setting either without `image_url` is rejected.

        - `Caption string`

          Primary label, top-left and bold.

        - `ImageSubtitle string`

          Text shown below `image_title`, overlaid on the card image. Requires `image_url`.

        - `ImageTitle string`

          Bold text overlaid on the card image. Requires `image_url` (rejected without it).

        - `ImageURL string`

          URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.

        - `Subcaption string`

          Secondary label, below `caption` on the left.

        - `TrailingCaption string`

          Label shown top-right.

        - `TrailingSubcaption string`

          Label shown below `trailing_caption`, on the right.

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an iMessage app card part.

        - `const MessagePartIMessageAppPartResponseTypeIMessageApp MessagePartIMessageAppPartResponseType = "imessage_app"`

      - `URL string`

        The URL delivered to the iMessage app on tap.

      - `FallbackText string`

        Fallback text for surfaces that cannot render the card.

    - `type MessagePartAppClipPartResponse struct{…}`

      An App Clip card part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an App Clip card part

        - `const MessagePartAppClipPartResponseTypeAppClip MessagePartAppClipPartResponseType = "app_clip"`

      - `Value string`

        The App Clip link the card opens

      - `Description string`

        The card's summary line, composed by Linq from the App Clip page

      - `ImageURL string`

        The card's preview image

      - `Title string`

        The card's headline, composed by Linq from the App Clip page

  - `PreferredService ServiceType`

    Messaging service type

  - `ReadAt Time`

    When the message was read

  - `ReconciledAt Time`

    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 — the message is genuine but was ingested late, so it may not have appeared in earlier reads of this conversation.

  - `ReplyTo ReplyTo`

    Indicates this message is a threaded reply to another message

    - `MessageID string`

      The ID of the message to reply to

    - `PartIndex int64`

      The specific message part to reply to (0-based index).
      Defaults to 0 (first part) if not provided.
      Use this when replying to a specific part of a multipart message.

  - `SentAt Time`

    When the message was sent

  - `Service ServiceType`

    Messaging service type

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  page, err := client.Messages.ListMessagesThread(
    context.TODO(),
    "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    linqgo.MessageListMessagesThreadParams{

    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", page)
}
```

#### Response

```json
{
  "messages": [
    {
      "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
      "chat_id": "94c6bf33-31d9-40e3-a0e9-f94250ecedb9",
      "created_at": "2024-01-15T10:30:00Z",
      "delivery_status": "pending",
      "is_delivered": true,
      "is_from_me": true,
      "is_read": false,
      "updated_at": "2024-01-15T10:30:00Z",
      "delivered_at": "2024-01-15T10:30:10Z",
      "effect": {
        "name": "confetti",
        "type": "screen"
      },
      "from": "+12052535597",
      "from_handle": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "handle": "+15551234567",
        "joined_at": "2025-05-21T15:30:00.000-05:00",
        "service": "iMessage",
        "is_me": false,
        "left_at": "2019-12-27T18:11:19.117Z",
        "status": "active"
      },
      "parts": [
        {
          "reactions": [
            {
              "handle": {
                "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
                "handle": "+15551234567",
                "joined_at": "2025-05-21T15:30:00.000-05:00",
                "service": "iMessage",
                "is_me": false,
                "left_at": "2019-12-27T18:11:19.117Z",
                "status": "active"
              },
              "is_me": false,
              "type": "love",
              "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
              "custom_emoji": null,
              "sticker": {
                "file_name": "sticker.png",
                "height": 420,
                "mime_type": "image/png",
                "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
                "width": 420
              }
            }
          ],
          "type": "text",
          "value": "Hello!",
          "mention": "+14155551234",
          "mention_range": [
            4,
            9
          ],
          "mentions": [
            {
              "handle": "+14155550123",
              "is_me": true,
              "range": [
                4,
                9
              ]
            }
          ],
          "text_decorations": [
            {
              "range": [
                0,
                5
              ],
              "animation": "shake",
              "style": "bold"
            }
          ]
        }
      ],
      "preferred_service": "iMessage",
      "read_at": "2024-01-15T10:35:00Z",
      "reconciled_at": "2024-01-15T14:05:00Z",
      "reply_to": {
        "message_id": "550e8400-e29b-41d4-a716-446655440000",
        "part_index": 0
      },
      "sent_at": "2024-01-15T10:30:05Z",
      "service": "iMessage"
    }
  ],
  "next_cursor": "eyJpZCI6IjEyMzQ1Njc4OTAiLCJ0cyI6MTYzMDUwMDAwMH0="
}
```

## Get a message by ID

`client.Messages.Get(ctx, messageID) (*Message, error)`

**get** `/v3/messages/{messageId}`

Retrieve a specific message by its ID. This endpoint returns the full message
details including text, attachments, reactions, and metadata.

### Parameters

- `messageID string`

### Returns

- `type Message struct{…}`

  - `ID string`

    Unique identifier for the message

  - `ChatID string`

    ID of the chat this message belongs to

  - `CreatedAt Time`

    When the message was created

  - `DeliveryStatus MessageDeliveryStatus`

    Current delivery status of a message

    - `const MessageDeliveryStatusPending MessageDeliveryStatus = "pending"`

    - `const MessageDeliveryStatusQueued MessageDeliveryStatus = "queued"`

    - `const MessageDeliveryStatusSent MessageDeliveryStatus = "sent"`

    - `const MessageDeliveryStatusDelivered MessageDeliveryStatus = "delivered"`

    - `const MessageDeliveryStatusReceived MessageDeliveryStatus = "received"`

    - `const MessageDeliveryStatusRead MessageDeliveryStatus = "read"`

    - `const MessageDeliveryStatusFailed MessageDeliveryStatus = "failed"`

  - `IsDelivered bool`

    DEPRECATED: Use `delivery_status` instead (true when `delivery_status` is `delivered` or `read`). Whether the message has been delivered.

  - `IsFromMe bool`

    Whether this message was sent by the authenticated user

  - `IsRead bool`

    DEPRECATED: Use `delivery_status == "read"` instead. Whether the message has been read.

  - `UpdatedAt Time`

    When the message was last updated

  - `DeliveredAt Time`

    When the message was delivered

  - `Effect MessageEffect`

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

    - `Name string`

      Name of the effect. Common values:

      - Screen effects: confetti, fireworks, lasers, sparkles, celebration, hearts, love, balloons, happy_birthday, echo, spotlight
      - Bubble effects: slam, loud, gentle, invisible

    - `Type MessageEffectType`

      Type of effect

      - `const MessageEffectTypeScreen MessageEffectType = "screen"`

      - `const MessageEffectTypeBubble MessageEffectType = "bubble"`

  - `From string`

    DEPRECATED: Use from_handle instead. Phone number of the message sender.

  - `FromHandle ChatHandle`

    The sender of this message as a full handle object

    - `ID string`

      Unique identifier for this handle

    - `Handle string`

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

    - `JoinedAt Time`

      When this participant joined the chat

    - `Service ServiceType`

      Messaging service type

      - `const ServiceTypeIMessage ServiceType = "iMessage"`

      - `const ServiceTypeSMS ServiceType = "SMS"`

      - `const ServiceTypeRCS ServiceType = "RCS"`

    - `IsMe bool`

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

    - `LeftAt Time`

      When they left (if applicable)

    - `Status ChatHandleStatus`

      Participant status

      - `const ChatHandleStatusActive ChatHandleStatus = "active"`

      - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

      - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

  - `Parts []MessagePartUnion`

    Message parts in order (text, media, and link)

    - `type TextPartResponse struct{…}`

      A text message part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

          - `const ReactionTypeLove ReactionType = "love"`

          - `const ReactionTypeLike ReactionType = "like"`

          - `const ReactionTypeDislike ReactionType = "dislike"`

          - `const ReactionTypeLaugh ReactionType = "laugh"`

          - `const ReactionTypeEmphasize ReactionType = "emphasize"`

          - `const ReactionTypeQuestion ReactionType = "question"`

          - `const ReactionTypeCustom ReactionType = "custom"`

          - `const ReactionTypeSticker ReactionType = "sticker"`

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

          - `FileName string`

            Filename of the sticker

          - `Height int64`

            Sticker image height in pixels

          - `MimeType string`

            MIME type of the sticker image

          - `URL string`

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

          - `Width int64`

            Sticker image width in pixels

      - `Type TextPartResponseType`

        Indicates this is a text message part

        - `const TextPartResponseTypeText TextPartResponseType = "text"`

      - `Value string`

        The text content

      - `Mention string`

        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.

      - `MentionRange []int64`

        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 []TextPartResponseMention`

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

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

        - `IsMe bool`

          Whether the mentioned participant is this line.

        - `Range []int64`

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

      - `TextDecorations []TextDecoration`

        Text decorations applied to character ranges in the value

        - `Range []int64`

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

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

          - `const TextDecorationAnimationBig TextDecorationAnimation = "big"`

          - `const TextDecorationAnimationSmall TextDecorationAnimation = "small"`

          - `const TextDecorationAnimationShake TextDecorationAnimation = "shake"`

          - `const TextDecorationAnimationNod TextDecorationAnimation = "nod"`

          - `const TextDecorationAnimationExplode TextDecorationAnimation = "explode"`

          - `const TextDecorationAnimationRipple TextDecorationAnimation = "ripple"`

          - `const TextDecorationAnimationBloom TextDecorationAnimation = "bloom"`

          - `const TextDecorationAnimationJitter TextDecorationAnimation = "jitter"`

        - `Style TextDecorationStyle`

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

          - `const TextDecorationStyleBold TextDecorationStyle = "bold"`

          - `const TextDecorationStyleItalic TextDecorationStyle = "italic"`

          - `const TextDecorationStyleStrikethrough TextDecorationStyle = "strikethrough"`

          - `const TextDecorationStyleUnderline TextDecorationStyle = "underline"`

    - `type MediaPartResponse struct{…}`

      A media attachment part

      - `ID string`

        Unique attachment identifier

      - `Filename string`

        Original filename

      - `MimeType string`

        MIME type of the file

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `SizeBytes int64`

        File size in bytes

      - `Type MediaPartResponseType`

        Indicates this is a media attachment part

        - `const MediaPartResponseTypeMedia MediaPartResponseType = "media"`

      - `URL string`

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

    - `type LinkPartResponse struct{…}`

      A rich link preview part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type LinkPartResponseType`

        Indicates this is a rich link preview part

        - `const LinkPartResponseTypeLink LinkPartResponseType = "link"`

      - `Value string`

        The URL

    - `type MessagePartIMessageAppPartResponse struct{…}`

      An iMessage app card part.

      - `App MessagePartIMessageAppPartResponseApp`

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

        - `BundleID string`

          Bundle identifier of the Messages app extension. Must not contain `:`.

        - `Name string`

          Display name of the app, shown by Messages' fallback UI.

        - `TeamID string`

          The app's 10-character uppercase alphanumeric team identifier.

        - `AppStoreID int64`

          The owning app's App Store id (optional). When set, recipients without the iMessage app
          installed see a "Get the app" affordance.

      - `Layout MessagePartIMessageAppPartResponseLayout`

        Visible layout of the card. At least one of
        `caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be
        set, otherwise the card renders as an empty bubble.

        `image_url` displays a preview image at the top of the card. The image renders on the
        recipient's card whether or not they have your app installed. The small icon beside the
        caption is the app's own icon and is not settable here.

        `* Note - requires a trusted chat w/ inbound activity`

        `image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle
        beneath it). They only appear when `image_url` is set — without an image there is nothing to
        overlay — so setting either without `image_url` is rejected.

        - `Caption string`

          Primary label, top-left and bold.

        - `ImageSubtitle string`

          Text shown below `image_title`, overlaid on the card image. Requires `image_url`.

        - `ImageTitle string`

          Bold text overlaid on the card image. Requires `image_url` (rejected without it).

        - `ImageURL string`

          URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.

        - `Subcaption string`

          Secondary label, below `caption` on the left.

        - `TrailingCaption string`

          Label shown top-right.

        - `TrailingSubcaption string`

          Label shown below `trailing_caption`, on the right.

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an iMessage app card part.

        - `const MessagePartIMessageAppPartResponseTypeIMessageApp MessagePartIMessageAppPartResponseType = "imessage_app"`

      - `URL string`

        The URL delivered to the iMessage app on tap.

      - `FallbackText string`

        Fallback text for surfaces that cannot render the card.

    - `type MessagePartAppClipPartResponse struct{…}`

      An App Clip card part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an App Clip card part

        - `const MessagePartAppClipPartResponseTypeAppClip MessagePartAppClipPartResponseType = "app_clip"`

      - `Value string`

        The App Clip link the card opens

      - `Description string`

        The card's summary line, composed by Linq from the App Clip page

      - `ImageURL string`

        The card's preview image

      - `Title string`

        The card's headline, composed by Linq from the App Clip page

  - `PreferredService ServiceType`

    Messaging service type

  - `ReadAt Time`

    When the message was read

  - `ReconciledAt Time`

    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 — the message is genuine but was ingested late, so it may not have appeared in earlier reads of this conversation.

  - `ReplyTo ReplyTo`

    Indicates this message is a threaded reply to another message

    - `MessageID string`

      The ID of the message to reply to

    - `PartIndex int64`

      The specific message part to reply to (0-based index).
      Defaults to 0 (first part) if not provided.
      Use this when replying to a specific part of a multipart message.

  - `SentAt Time`

    When the message was sent

  - `Service ServiceType`

    Messaging service type

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  message, err := client.Messages.Get(context.TODO(), "69a37c7d-af4f-4b5e-af42-e28e98ce873a")
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", message.ID)
}
```

#### Response

```json
{
  "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
  "chat_id": "94c6bf33-31d9-40e3-a0e9-f94250ecedb9",
  "created_at": "2024-01-15T10:30:00Z",
  "delivery_status": "pending",
  "is_delivered": true,
  "is_from_me": true,
  "is_read": false,
  "updated_at": "2024-01-15T10:30:00Z",
  "delivered_at": "2024-01-15T10:30:10Z",
  "effect": {
    "name": "confetti",
    "type": "screen"
  },
  "from": "+12052535597",
  "from_handle": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "handle": "+15551234567",
    "joined_at": "2025-05-21T15:30:00.000-05:00",
    "service": "iMessage",
    "is_me": false,
    "left_at": "2019-12-27T18:11:19.117Z",
    "status": "active"
  },
  "parts": [
    {
      "reactions": [
        {
          "handle": {
            "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
            "handle": "+15551234567",
            "joined_at": "2025-05-21T15:30:00.000-05:00",
            "service": "iMessage",
            "is_me": false,
            "left_at": "2019-12-27T18:11:19.117Z",
            "status": "active"
          },
          "is_me": false,
          "type": "love",
          "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
          "custom_emoji": null,
          "sticker": {
            "file_name": "sticker.png",
            "height": 420,
            "mime_type": "image/png",
            "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
            "width": 420
          }
        }
      ],
      "type": "text",
      "value": "Hello!",
      "mention": "+14155551234",
      "mention_range": [
        4,
        9
      ],
      "mentions": [
        {
          "handle": "+14155550123",
          "is_me": true,
          "range": [
            4,
            9
          ]
        }
      ],
      "text_decorations": [
        {
          "range": [
            0,
            5
          ],
          "animation": "shake",
          "style": "bold"
        }
      ]
    }
  ],
  "preferred_service": "iMessage",
  "read_at": "2024-01-15T10:35:00Z",
  "reconciled_at": "2024-01-15T14:05:00Z",
  "reply_to": {
    "message_id": "550e8400-e29b-41d4-a716-446655440000",
    "part_index": 0
  },
  "sent_at": "2024-01-15T10:30:05Z",
  "service": "iMessage"
}
```

## Delete a message from system

`client.Messages.Delete(ctx, messageID) error`

**delete** `/v3/messages/{messageId}`

Deletes a message from the Linq API only. This does NOT unsend or remove the message
from the actual chat — recipients will still see the message.
Re-sending with a deleted message's idempotency key returns 404 — a deleted message is never resent.

### Parameters

- `messageID string`

### Example

```go
package main

import (
  "context"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  err := client.Messages.Delete(context.TODO(), "69a37c7d-af4f-4b5e-af42-e28e98ce873a")
  if err != nil {
    panic(err.Error())
  }
}
```

#### Response

```json
{
  "error": {
    "status": 400,
    "code": 1002,
    "message": "Phone number must be in E.164 format",
    "doc_url": "https://docs.linqapp.com/channel/imessage/error/codes/1xxx/1002/"
  },
  "success": false
}
```

## Add or remove a reaction to a message

`client.Messages.AddReaction(ctx, messageID, body) (*MessageAddReactionResponse, error)`

**post** `/v3/messages/{messageId}/reactions`

Add or remove emoji reactions to messages. Reactions let users express
their response to a message without sending a new message.

**Supported Reactions:**

- love ❤️
- like 👍
- dislike 👎
- laugh 😂
- emphasize ‼️
- question ❓
- custom - any emoji (use `custom_emoji` field to specify)
- sticker - an image peeled onto the message (use `url` or `attachment_id`)

**Stickers** are iMessage-only and cannot be removed — iMessage has no
unpeel operation, so `operation: "remove"` with `type: "sticker"` is
rejected. Position, size and rotation are optional via `placement`, and can
be changed afterwards with
`PATCH /v3/messages/{messageId}/reactions/{reactionId}`.

### Parameters

- `messageID string`

- `body MessageAddReactionParams`

  - `Operation param.Field[MessageAddReactionParamsOperation]`

    Whether to add or remove the reaction

    - `const MessageAddReactionParamsOperationAdd MessageAddReactionParamsOperation = "add"`

    - `const MessageAddReactionParamsOperationRemove MessageAddReactionParamsOperation = "remove"`

  - `Type param.Field[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.

  - `AttachmentID param.Field[string]`

    Reference to a sticker image pre-uploaded via `POST /v3/attachments`.
    Only valid when type is "sticker".

    Either `url` or `attachment_id` must be provided when type is
    "sticker", but not both.

  - `CustomEmoji param.Field[string]`

    Custom emoji string. Required when type is "custom".

  - `PartIndex param.Field[int64]`

    Optional index of the message part to react to.
    If not provided, reacts to the entire message (part 0).

  - `Placement param.Field[MessageAddReactionParamsPlacement]`

    Optional position, size and rotation of a sticker on the target
    bubble. Only valid when type is "sticker".

    Every field is independent and optional — omit the object entirely,
    or any field within it, to keep the default (centred, default size,
    unrotated).

    - `Rotation float64`

      Clockwise rotation in degrees.

    - `Scale float64`

      Size relative to the default, where 1 matches the size a
      sticker gets natively.

      Values outside 0.5–1.5 are clamped rather than rejected. The
      upper bound keeps a sticker within the size range iMessage
      itself displays: its own limit is larger, but that allowance
      assumes the transparent padding Apple's stickers carry, which
      a full-bleed image does not have.

      Scale is linear, so 1.5 is a little over twice the area.

    - `X float64`

      Horizontal position on the target bubble, from -1 (far left) to
      1 (far right). 0 is centred.

    - `Y float64`

      Vertical position on the target bubble, from -1 (top) to
      1 (bottom). 0 is centred.

  - `URL param.Field[string]`

    Linq attachment URL of the sticker image — the `download_url`
    returned by `POST /v3/attachments`. Only valid when type is
    "sticker".

    Unlike a media part, this does **not** accept an arbitrary host:
    reactions have no download step, so the image must already be
    stored. To send a sticker from elsewhere, upload it with
    `POST /v3/attachments` first and pass `attachment_id`.

    Either `url` or `attachment_id` must be provided when type is
    "sticker", but not both.

### Returns

- `type MessageAddReactionResponse struct{…}`

  - `Message string`

  - `Status string`

  - `TraceID string`

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
  "github.com/linq-team/linq-go/shared"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  response, err := client.Messages.AddReaction(
    context.TODO(),
    "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    linqgo.MessageAddReactionParams{
      Operation: linqgo.MessageAddReactionParamsOperationAdd,
      Type: shared.ReactionTypeLove,
    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", response.TraceID)
}
```

#### Response

```json
{
  "message": "Reaction processed",
  "status": "accepted",
  "trace_id": "trace_id"
}
```

## Move a sticker already on a message

`client.Messages.UpdateStickerPlacement(ctx, reactionID, params) (*MessageUpdateStickerPlacementResponse, error)`

**patch** `/v3/messages/{messageId}/reactions/{reactionId}`

Move, resize or rotate a sticker that has already been peeled onto a message.
The change is sent to every device in the conversation, exactly as dragging the
sticker by hand would.

Only stickers can be repositioned — a tapback has no placement, so a non-sticker
`reactionId` is rejected. Any field omitted from `placement` keeps its current value.

`reactionId` is the `id` from the reaction on the message, or from the
`reaction.added` webhook. Stickers stack, so this id is what distinguishes one
sticker from another on the same message.

Stickers peeled before this endpoint existed cannot be moved: addressing one
requires an identifier that was not recorded at the time, and it returns 404.

### Parameters

- `reactionID string`

- `params MessageUpdateStickerPlacementParams`

  - `MessageID param.Field[string]`

    Path param: The message the sticker sits on

  - `Placement param.Field[MessageUpdateStickerPlacementParamsPlacement]`

    Body param: Optional position, size and rotation of a sticker on the target
    bubble. Only valid when type is "sticker".

    Every field is independent and optional — omit the object entirely,
    or any field within it, to keep the default (centred, default size,
    unrotated).

    - `Rotation float64`

      Clockwise rotation in degrees.

    - `Scale float64`

      Size relative to the default, where 1 matches the size a
      sticker gets natively.

      Values outside 0.5–1.5 are clamped rather than rejected. The
      upper bound keeps a sticker within the size range iMessage
      itself displays: its own limit is larger, but that allowance
      assumes the transparent padding Apple's stickers carry, which
      a full-bleed image does not have.

      Scale is linear, so 1.5 is a little over twice the area.

    - `X float64`

      Horizontal position on the target bubble, from -1 (far left) to
      1 (far right). 0 is centred.

    - `Y float64`

      Vertical position on the target bubble, from -1 (top) to
      1 (bottom). 0 is centred.

### Returns

- `type MessageUpdateStickerPlacementResponse struct{…}`

  - `Status string`

  - `Success bool`

  - `TraceID string`

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  response, err := client.Messages.UpdateStickerPlacement(
    context.TODO(),
    "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
    linqgo.MessageUpdateStickerPlacementParams{
      MessageID: "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
      Placement: linqgo.MessageUpdateStickerPlacementParamsPlacement{
        X: linqgo.Float(0.6),
        Y: linqgo.Float(0.5),
        Scale: linqgo.Float(0.75),
      },
    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", response.TraceID)
}
```

#### Response

```json
{
  "status": "accepted",
  "success": true,
  "trace_id": "trace_id"
}
```

## Edit the content of a message part

`client.Messages.Update(ctx, messageID, body) (*Message, error)`

**patch** `/v3/messages/{messageId}`

Edit the text content of a specific part of a previously sent message.

**Note:** A message can be edited up to 5 times, and only within 15 minutes of when it was originally sent.

### Parameters

- `messageID string`

- `body MessageUpdateParams`

  - `Text param.Field[string]`

    New text content for the message part

  - `PartIndex param.Field[int64]`

    Index of the message part to edit. Defaults to 0.

### Returns

- `type Message struct{…}`

  - `ID string`

    Unique identifier for the message

  - `ChatID string`

    ID of the chat this message belongs to

  - `CreatedAt Time`

    When the message was created

  - `DeliveryStatus MessageDeliveryStatus`

    Current delivery status of a message

    - `const MessageDeliveryStatusPending MessageDeliveryStatus = "pending"`

    - `const MessageDeliveryStatusQueued MessageDeliveryStatus = "queued"`

    - `const MessageDeliveryStatusSent MessageDeliveryStatus = "sent"`

    - `const MessageDeliveryStatusDelivered MessageDeliveryStatus = "delivered"`

    - `const MessageDeliveryStatusReceived MessageDeliveryStatus = "received"`

    - `const MessageDeliveryStatusRead MessageDeliveryStatus = "read"`

    - `const MessageDeliveryStatusFailed MessageDeliveryStatus = "failed"`

  - `IsDelivered bool`

    DEPRECATED: Use `delivery_status` instead (true when `delivery_status` is `delivered` or `read`). Whether the message has been delivered.

  - `IsFromMe bool`

    Whether this message was sent by the authenticated user

  - `IsRead bool`

    DEPRECATED: Use `delivery_status == "read"` instead. Whether the message has been read.

  - `UpdatedAt Time`

    When the message was last updated

  - `DeliveredAt Time`

    When the message was delivered

  - `Effect MessageEffect`

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

    - `Name string`

      Name of the effect. Common values:

      - Screen effects: confetti, fireworks, lasers, sparkles, celebration, hearts, love, balloons, happy_birthday, echo, spotlight
      - Bubble effects: slam, loud, gentle, invisible

    - `Type MessageEffectType`

      Type of effect

      - `const MessageEffectTypeScreen MessageEffectType = "screen"`

      - `const MessageEffectTypeBubble MessageEffectType = "bubble"`

  - `From string`

    DEPRECATED: Use from_handle instead. Phone number of the message sender.

  - `FromHandle ChatHandle`

    The sender of this message as a full handle object

    - `ID string`

      Unique identifier for this handle

    - `Handle string`

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

    - `JoinedAt Time`

      When this participant joined the chat

    - `Service ServiceType`

      Messaging service type

      - `const ServiceTypeIMessage ServiceType = "iMessage"`

      - `const ServiceTypeSMS ServiceType = "SMS"`

      - `const ServiceTypeRCS ServiceType = "RCS"`

    - `IsMe bool`

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

    - `LeftAt Time`

      When they left (if applicable)

    - `Status ChatHandleStatus`

      Participant status

      - `const ChatHandleStatusActive ChatHandleStatus = "active"`

      - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

      - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

  - `Parts []MessagePartUnion`

    Message parts in order (text, media, and link)

    - `type TextPartResponse struct{…}`

      A text message part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

          - `const ReactionTypeLove ReactionType = "love"`

          - `const ReactionTypeLike ReactionType = "like"`

          - `const ReactionTypeDislike ReactionType = "dislike"`

          - `const ReactionTypeLaugh ReactionType = "laugh"`

          - `const ReactionTypeEmphasize ReactionType = "emphasize"`

          - `const ReactionTypeQuestion ReactionType = "question"`

          - `const ReactionTypeCustom ReactionType = "custom"`

          - `const ReactionTypeSticker ReactionType = "sticker"`

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

          - `FileName string`

            Filename of the sticker

          - `Height int64`

            Sticker image height in pixels

          - `MimeType string`

            MIME type of the sticker image

          - `URL string`

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

          - `Width int64`

            Sticker image width in pixels

      - `Type TextPartResponseType`

        Indicates this is a text message part

        - `const TextPartResponseTypeText TextPartResponseType = "text"`

      - `Value string`

        The text content

      - `Mention string`

        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.

      - `MentionRange []int64`

        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 []TextPartResponseMention`

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

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

        - `IsMe bool`

          Whether the mentioned participant is this line.

        - `Range []int64`

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

      - `TextDecorations []TextDecoration`

        Text decorations applied to character ranges in the value

        - `Range []int64`

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

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

          - `const TextDecorationAnimationBig TextDecorationAnimation = "big"`

          - `const TextDecorationAnimationSmall TextDecorationAnimation = "small"`

          - `const TextDecorationAnimationShake TextDecorationAnimation = "shake"`

          - `const TextDecorationAnimationNod TextDecorationAnimation = "nod"`

          - `const TextDecorationAnimationExplode TextDecorationAnimation = "explode"`

          - `const TextDecorationAnimationRipple TextDecorationAnimation = "ripple"`

          - `const TextDecorationAnimationBloom TextDecorationAnimation = "bloom"`

          - `const TextDecorationAnimationJitter TextDecorationAnimation = "jitter"`

        - `Style TextDecorationStyle`

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

          - `const TextDecorationStyleBold TextDecorationStyle = "bold"`

          - `const TextDecorationStyleItalic TextDecorationStyle = "italic"`

          - `const TextDecorationStyleStrikethrough TextDecorationStyle = "strikethrough"`

          - `const TextDecorationStyleUnderline TextDecorationStyle = "underline"`

    - `type MediaPartResponse struct{…}`

      A media attachment part

      - `ID string`

        Unique attachment identifier

      - `Filename string`

        Original filename

      - `MimeType string`

        MIME type of the file

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `SizeBytes int64`

        File size in bytes

      - `Type MediaPartResponseType`

        Indicates this is a media attachment part

        - `const MediaPartResponseTypeMedia MediaPartResponseType = "media"`

      - `URL string`

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

    - `type LinkPartResponse struct{…}`

      A rich link preview part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type LinkPartResponseType`

        Indicates this is a rich link preview part

        - `const LinkPartResponseTypeLink LinkPartResponseType = "link"`

      - `Value string`

        The URL

    - `type MessagePartIMessageAppPartResponse struct{…}`

      An iMessage app card part.

      - `App MessagePartIMessageAppPartResponseApp`

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

        - `BundleID string`

          Bundle identifier of the Messages app extension. Must not contain `:`.

        - `Name string`

          Display name of the app, shown by Messages' fallback UI.

        - `TeamID string`

          The app's 10-character uppercase alphanumeric team identifier.

        - `AppStoreID int64`

          The owning app's App Store id (optional). When set, recipients without the iMessage app
          installed see a "Get the app" affordance.

      - `Layout MessagePartIMessageAppPartResponseLayout`

        Visible layout of the card. At least one of
        `caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be
        set, otherwise the card renders as an empty bubble.

        `image_url` displays a preview image at the top of the card. The image renders on the
        recipient's card whether or not they have your app installed. The small icon beside the
        caption is the app's own icon and is not settable here.

        `* Note - requires a trusted chat w/ inbound activity`

        `image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle
        beneath it). They only appear when `image_url` is set — without an image there is nothing to
        overlay — so setting either without `image_url` is rejected.

        - `Caption string`

          Primary label, top-left and bold.

        - `ImageSubtitle string`

          Text shown below `image_title`, overlaid on the card image. Requires `image_url`.

        - `ImageTitle string`

          Bold text overlaid on the card image. Requires `image_url` (rejected without it).

        - `ImageURL string`

          URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.

        - `Subcaption string`

          Secondary label, below `caption` on the left.

        - `TrailingCaption string`

          Label shown top-right.

        - `TrailingSubcaption string`

          Label shown below `trailing_caption`, on the right.

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an iMessage app card part.

        - `const MessagePartIMessageAppPartResponseTypeIMessageApp MessagePartIMessageAppPartResponseType = "imessage_app"`

      - `URL string`

        The URL delivered to the iMessage app on tap.

      - `FallbackText string`

        Fallback text for surfaces that cannot render the card.

    - `type MessagePartAppClipPartResponse struct{…}`

      An App Clip card part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an App Clip card part

        - `const MessagePartAppClipPartResponseTypeAppClip MessagePartAppClipPartResponseType = "app_clip"`

      - `Value string`

        The App Clip link the card opens

      - `Description string`

        The card's summary line, composed by Linq from the App Clip page

      - `ImageURL string`

        The card's preview image

      - `Title string`

        The card's headline, composed by Linq from the App Clip page

  - `PreferredService ServiceType`

    Messaging service type

  - `ReadAt Time`

    When the message was read

  - `ReconciledAt Time`

    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 — the message is genuine but was ingested late, so it may not have appeared in earlier reads of this conversation.

  - `ReplyTo ReplyTo`

    Indicates this message is a threaded reply to another message

    - `MessageID string`

      The ID of the message to reply to

    - `PartIndex int64`

      The specific message part to reply to (0-based index).
      Defaults to 0 (first part) if not provided.
      Use this when replying to a specific part of a multipart message.

  - `SentAt Time`

    When the message was sent

  - `Service ServiceType`

    Messaging service type

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  message, err := client.Messages.Update(
    context.TODO(),
    "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    linqgo.MessageUpdateParams{
      Text: "This is the edited message content",
    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", message.ID)
}
```

#### Response

```json
{
  "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
  "chat_id": "94c6bf33-31d9-40e3-a0e9-f94250ecedb9",
  "created_at": "2024-01-15T10:30:00Z",
  "delivery_status": "pending",
  "is_delivered": true,
  "is_from_me": true,
  "is_read": false,
  "updated_at": "2024-01-15T10:30:00Z",
  "delivered_at": "2024-01-15T10:30:10Z",
  "effect": {
    "name": "confetti",
    "type": "screen"
  },
  "from": "+12052535597",
  "from_handle": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "handle": "+15551234567",
    "joined_at": "2025-05-21T15:30:00.000-05:00",
    "service": "iMessage",
    "is_me": false,
    "left_at": "2019-12-27T18:11:19.117Z",
    "status": "active"
  },
  "parts": [
    {
      "reactions": [
        {
          "handle": {
            "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
            "handle": "+15551234567",
            "joined_at": "2025-05-21T15:30:00.000-05:00",
            "service": "iMessage",
            "is_me": false,
            "left_at": "2019-12-27T18:11:19.117Z",
            "status": "active"
          },
          "is_me": false,
          "type": "love",
          "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
          "custom_emoji": null,
          "sticker": {
            "file_name": "sticker.png",
            "height": 420,
            "mime_type": "image/png",
            "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
            "width": 420
          }
        }
      ],
      "type": "text",
      "value": "Hello!",
      "mention": "+14155551234",
      "mention_range": [
        4,
        9
      ],
      "mentions": [
        {
          "handle": "+14155550123",
          "is_me": true,
          "range": [
            4,
            9
          ]
        }
      ],
      "text_decorations": [
        {
          "range": [
            0,
            5
          ],
          "animation": "shake",
          "style": "bold"
        }
      ]
    }
  ],
  "preferred_service": "iMessage",
  "read_at": "2024-01-15T10:35:00Z",
  "reconciled_at": "2024-01-15T14:05:00Z",
  "reply_to": {
    "message_id": "550e8400-e29b-41d4-a716-446655440000",
    "part_index": 0
  },
  "sent_at": "2024-01-15T10:30:05Z",
  "service": "iMessage"
}
```

## Update an iMessage app card in place

`client.Messages.UpdateAppCard(ctx, messageID, body) (*MessageUpdateAppCardResponse, error)`

**post** `/v3/messages/{messageId}/update`

Replaces a previously delivered `imessage_app` card on the recipient's screen with new
content, instead of posting a new bubble (like a game move redrawing the board).

The update is delivered as a **new message** with its own id and delivery lifecycle
(`message.sent` / `message.delivered` / `message.failed` webhooks fire for the new id).
To update the card again, reference the message id returned by this call.

Constraints:

- The referenced message must be an `imessage_app` card sent by you (`400` otherwise —
  inbound cards cannot be updated).
- The referenced card must already be delivered (`409` otherwise — retry after the
  `message.delivered` webhook for it).
- The app identity (`team_id`, `bundle_id`, name) is inherited from the original card and
  cannot change; only `url`, `fallback_text`, and `layout` are replaced.
- iMessage-only, like all app cards.
- Concurrent updates against the same card are not serialized server-side; the last one
  delivered wins on the recipient's screen. Serialize updates by always referencing the
  message id returned by the previous call.

### Parameters

- `messageID string`

- `body MessageUpdateAppCardParams`

  - `Layout param.Field[MessageUpdateAppCardParamsLayout]`

    Visible layout of the card. At least one of
    `caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be
    set, otherwise the card renders as an empty bubble.

    `image_url` displays a preview image at the top of the card. The image renders on the
    recipient's card whether or not they have your app installed. The small icon beside the
    caption is the app's own icon and is not settable here.

    `* Note - requires a trusted chat w/ inbound activity`

    `image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle
    beneath it). They only appear when `image_url` is set — without an image there is nothing to
    overlay — so setting either without `image_url` is rejected.

    - `Caption string`

      Primary label, top-left and bold.

    - `ImageSubtitle string`

      Text shown below `image_title`, overlaid on the card image. Requires `image_url`.

    - `ImageTitle string`

      Bold text overlaid on the card image. Requires `image_url` (rejected without it).

    - `ImageURL string`

      URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.

    - `Subcaption string`

      Secondary label, below `caption` on the left.

    - `TrailingCaption string`

      Label shown top-right.

    - `TrailingSubcaption string`

      Label shown below `trailing_caption`, on the right.

  - `App param.Field[MessageUpdateAppCardParamsApp]`

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

    - `BundleID string`

      Bundle identifier of the Messages app extension. Must not contain `:`.

    - `Name string`

      Display name of the app, shown by Messages' fallback UI.

    - `TeamID string`

      The app's 10-character uppercase alphanumeric team identifier.

    - `AppStoreID int64`

      The owning app's App Store id (optional). When set, recipients without the iMessage app
      installed see a "Get the app" affordance.

  - `Experience param.Field[MessageUpdateAppCardParamsExperience]`

    Invokes an action on an experience — a third party that renders inside
    Linq's iMessage app. Linq resolves the recipient's connection, mints any
    session the action needs, composes the card and sends it; none of that
    is visible to you.

    Call `GET /v3/experiences/{experience}` for the actions you may invoke
    and the fields each accepts.

    - `Action string`

      Which of its actions, e.g. `attach_card`.

    - `Name string`

      The experience to invoke, e.g. `agentcard` or `agentpay`.

    - `Params map[string, any]`

      Values for the fields this action exposes. Keys are exactly the
      field names listed for the action — no mapping, no nesting.

      Display copy only, except a `url`-type field — that value sets the
      destination, and must be an absolute `https` URL.

      Some fields are read rather than sent: `agentpay`'s
      `request_payment` takes only a `checkout_url` and resolves the
      amount and reason from that payment request itself, so the card
      cannot state a figure the checkout will not charge.

  - `FallbackText param.Field[string]`

    Text shown on surfaces that cannot render the card (notifications, lock screen). Defaults
    to the caption when omitted.

  - `Interactive param.Field[bool]`

    Whether the updated card renders as your app's interactive balloon for recipients who
    have your iMessage app installed. `true` (default) lets your installed extension draw its
    live view; `false` always shows the static `layout` card. Recipients without your app
    always see the static card regardless of this flag.

    Defaults to `true` when omitted — it is **not** inherited from the original card. To keep a
    card static across updates, re-send `interactive: false` on each update.

  - `URL param.Field[string]`

    URL the recipient's app opens when they tap the updated card.

    Mutually exclusive with `experience` and `raw_payload_data`.

### Returns

- `type MessageUpdateAppCardResponse struct{…}`

  Response for sending a message to a chat

  - `ChatID string`

    Unique identifier of the chat this message was sent to

  - `Message SentMessage`

    A message that was sent (used in CreateChat and SendMessage responses)

    - `ID string`

      Message identifier (UUID)

    - `CreatedAt Time`

      When the message was created

    - `DeliveryStatus SentMessageDeliveryStatus`

      Current delivery status of a message

      - `const SentMessageDeliveryStatusPending SentMessageDeliveryStatus = "pending"`

      - `const SentMessageDeliveryStatusQueued SentMessageDeliveryStatus = "queued"`

      - `const SentMessageDeliveryStatusSent SentMessageDeliveryStatus = "sent"`

      - `const SentMessageDeliveryStatusDelivered SentMessageDeliveryStatus = "delivered"`

      - `const SentMessageDeliveryStatusReceived SentMessageDeliveryStatus = "received"`

      - `const SentMessageDeliveryStatusRead SentMessageDeliveryStatus = "read"`

      - `const SentMessageDeliveryStatusFailed SentMessageDeliveryStatus = "failed"`

    - `IsRead bool`

      DEPRECATED: Use `delivery_status == "read"` instead. Whether the message has been read.

    - `Parts []SentMessagePartUnion`

      Message parts in order (text, media, and link)

      - `type TextPartResponse struct{…}`

        A text message part

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

            - `ID string`

              Unique identifier for this handle

            - `Handle string`

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

            - `JoinedAt Time`

              When this participant joined the chat

            - `Service ServiceType`

              Messaging service type

              - `const ServiceTypeIMessage ServiceType = "iMessage"`

              - `const ServiceTypeSMS ServiceType = "SMS"`

              - `const ServiceTypeRCS ServiceType = "RCS"`

            - `IsMe bool`

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

            - `LeftAt Time`

              When they left (if applicable)

            - `Status ChatHandleStatus`

              Participant status

              - `const ChatHandleStatusActive ChatHandleStatus = "active"`

              - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

              - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

          - `IsMe bool`

            Whether this reaction is from the current user

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

            - `const ReactionTypeLove ReactionType = "love"`

            - `const ReactionTypeLike ReactionType = "like"`

            - `const ReactionTypeDislike ReactionType = "dislike"`

            - `const ReactionTypeLaugh ReactionType = "laugh"`

            - `const ReactionTypeEmphasize ReactionType = "emphasize"`

            - `const ReactionTypeQuestion ReactionType = "question"`

            - `const ReactionTypeCustom ReactionType = "custom"`

            - `const ReactionTypeSticker ReactionType = "sticker"`

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

            - `FileName string`

              Filename of the sticker

            - `Height int64`

              Sticker image height in pixels

            - `MimeType string`

              MIME type of the sticker image

            - `URL string`

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

            - `Width int64`

              Sticker image width in pixels

        - `Type TextPartResponseType`

          Indicates this is a text message part

          - `const TextPartResponseTypeText TextPartResponseType = "text"`

        - `Value string`

          The text content

        - `Mention string`

          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.

        - `MentionRange []int64`

          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 []TextPartResponseMention`

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

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

          - `IsMe bool`

            Whether the mentioned participant is this line.

          - `Range []int64`

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

        - `TextDecorations []TextDecoration`

          Text decorations applied to character ranges in the value

          - `Range []int64`

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

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

            - `const TextDecorationAnimationBig TextDecorationAnimation = "big"`

            - `const TextDecorationAnimationSmall TextDecorationAnimation = "small"`

            - `const TextDecorationAnimationShake TextDecorationAnimation = "shake"`

            - `const TextDecorationAnimationNod TextDecorationAnimation = "nod"`

            - `const TextDecorationAnimationExplode TextDecorationAnimation = "explode"`

            - `const TextDecorationAnimationRipple TextDecorationAnimation = "ripple"`

            - `const TextDecorationAnimationBloom TextDecorationAnimation = "bloom"`

            - `const TextDecorationAnimationJitter TextDecorationAnimation = "jitter"`

          - `Style TextDecorationStyle`

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

            - `const TextDecorationStyleBold TextDecorationStyle = "bold"`

            - `const TextDecorationStyleItalic TextDecorationStyle = "italic"`

            - `const TextDecorationStyleStrikethrough TextDecorationStyle = "strikethrough"`

            - `const TextDecorationStyleUnderline TextDecorationStyle = "underline"`

      - `type MediaPartResponse struct{…}`

        A media attachment part

        - `ID string`

          Unique attachment identifier

        - `Filename string`

          Original filename

        - `MimeType string`

          MIME type of the file

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `SizeBytes int64`

          File size in bytes

        - `Type MediaPartResponseType`

          Indicates this is a media attachment part

          - `const MediaPartResponseTypeMedia MediaPartResponseType = "media"`

        - `URL string`

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

      - `type LinkPartResponse struct{…}`

        A rich link preview part

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `Type LinkPartResponseType`

          Indicates this is a rich link preview part

          - `const LinkPartResponseTypeLink LinkPartResponseType = "link"`

        - `Value string`

          The URL

      - `type SentMessagePartIMessageAppPartResponse struct{…}`

        An iMessage app card part.

        - `App SentMessagePartIMessageAppPartResponseApp`

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

          - `BundleID string`

            Bundle identifier of the Messages app extension. Must not contain `:`.

          - `Name string`

            Display name of the app, shown by Messages' fallback UI.

          - `TeamID string`

            The app's 10-character uppercase alphanumeric team identifier.

          - `AppStoreID int64`

            The owning app's App Store id (optional). When set, recipients without the iMessage app
            installed see a "Get the app" affordance.

        - `Layout SentMessagePartIMessageAppPartResponseLayout`

          Visible layout of the card. At least one of
          `caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be
          set, otherwise the card renders as an empty bubble.

          `image_url` displays a preview image at the top of the card. The image renders on the
          recipient's card whether or not they have your app installed. The small icon beside the
          caption is the app's own icon and is not settable here.

          `* Note - requires a trusted chat w/ inbound activity`

          `image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle
          beneath it). They only appear when `image_url` is set — without an image there is nothing to
          overlay — so setting either without `image_url` is rejected.

          - `Caption string`

            Primary label, top-left and bold.

          - `ImageSubtitle string`

            Text shown below `image_title`, overlaid on the card image. Requires `image_url`.

          - `ImageTitle string`

            Bold text overlaid on the card image. Requires `image_url` (rejected without it).

          - `ImageURL string`

            URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.

          - `Subcaption string`

            Secondary label, below `caption` on the left.

          - `TrailingCaption string`

            Label shown top-right.

          - `TrailingSubcaption string`

            Label shown below `trailing_caption`, on the right.

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `Type string`

          Indicates this is an iMessage app card part.

          - `const SentMessagePartIMessageAppPartResponseTypeIMessageApp SentMessagePartIMessageAppPartResponseType = "imessage_app"`

        - `URL string`

          The URL delivered to the iMessage app on tap.

        - `FallbackText string`

          Fallback text for surfaces that cannot render the card.

      - `type SentMessagePartAppClipPartResponse struct{…}`

        An App Clip card part

        - `Reactions []Reaction`

          Reactions on this message part

          - `Handle ChatHandle`

          - `IsMe bool`

            Whether this reaction is from the current user

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

          - `ID string`

            Identifier for this reaction. Pass it to
            `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

            Stickers placed before this API shipped can be read but not moved: the
            device-side reference needed to reposition them was never recorded, so
            `PATCH` returns 404 for those.

          - `CustomEmoji string`

            Custom emoji if type is "custom", null otherwise

          - `Sticker ReactionSticker`

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

        - `Type string`

          Indicates this is an App Clip card part

          - `const SentMessagePartAppClipPartResponseTypeAppClip SentMessagePartAppClipPartResponseType = "app_clip"`

        - `Value string`

          The App Clip link the card opens

        - `Description string`

          The card's summary line, composed by Linq from the App Clip page

        - `ImageURL string`

          The card's preview image

        - `Title string`

          The card's headline, composed by Linq from the App Clip page

    - `SentAt Time`

      When the message was actually sent (null if still queued)

    - `DeliveredAt Time`

      When the message was delivered

    - `Effect MessageEffect`

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

      - `Name string`

        Name of the effect. Common values:

        - Screen effects: confetti, fireworks, lasers, sparkles, celebration, hearts, love, balloons, happy_birthday, echo, spotlight
        - Bubble effects: slam, loud, gentle, invisible

      - `Type MessageEffectType`

        Type of effect

        - `const MessageEffectTypeScreen MessageEffectType = "screen"`

        - `const MessageEffectTypeBubble MessageEffectType = "bubble"`

    - `FromHandle ChatHandle`

      The sender of this message as a full handle object

    - `PreferredService ServiceType`

      Messaging service type

    - `ReplyTo ReplyTo`

      Indicates this message is a threaded reply to another message

      - `MessageID string`

        The ID of the message to reply to

      - `PartIndex int64`

        The specific message part to reply to (0-based index).
        Defaults to 0 (first part) if not provided.
        Use this when replying to a specific part of a multipart message.

    - `Service ServiceType`

      Messaging service type

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  response, err := client.Messages.UpdateAppCard(
    context.TODO(),
    "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    linqgo.MessageUpdateAppCardParams{
      Layout: linqgo.MessageUpdateAppCardParamsLayout{
        Caption: linqgo.String("Score: 2 – 1"),
      },
      FallbackText: linqgo.String("Score update"),
      URL: linqgo.String("https://app.example.com/card?game=7f3a&move=2"),
    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", response.ChatID)
}
```

#### Response

```json
{
  "chat_id": "550e8400-e29b-41d4-a716-446655440000",
  "message": {
    "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    "created_at": "2025-10-23T13:07:55.019-05:00",
    "delivery_status": "pending",
    "is_read": false,
    "parts": [
      {
        "reactions": [
          {
            "handle": {
              "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
              "handle": "+15551234567",
              "joined_at": "2025-05-21T15:30:00.000-05:00",
              "service": "iMessage",
              "is_me": false,
              "left_at": "2019-12-27T18:11:19.117Z",
              "status": "active"
            },
            "is_me": false,
            "type": "love",
            "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
            "custom_emoji": null,
            "sticker": {
              "file_name": "sticker.png",
              "height": 420,
              "mime_type": "image/png",
              "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
              "width": 420
            }
          }
        ],
        "type": "text",
        "value": "Hello!",
        "mention": "+14155551234",
        "mention_range": [
          4,
          9
        ],
        "mentions": [
          {
            "handle": "+14155550123",
            "is_me": true,
            "range": [
              4,
              9
            ]
          }
        ],
        "text_decorations": [
          {
            "range": [
              0,
              5
            ],
            "animation": "shake",
            "style": "bold"
          }
        ]
      }
    ],
    "sent_at": null,
    "delivered_at": null,
    "effect": {
      "name": "confetti",
      "type": "screen"
    },
    "from_handle": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "handle": "+15551234567",
      "joined_at": "2025-05-21T15:30:00.000-05:00",
      "service": "iMessage",
      "is_me": false,
      "left_at": "2019-12-27T18:11:19.117Z",
      "status": "active"
    },
    "preferred_service": "iMessage",
    "reply_to": {
      "message_id": "550e8400-e29b-41d4-a716-446655440000",
      "part_index": 0
    },
    "service": "iMessage"
  }
}
```

## Domain Types

### Message

- `type Message struct{…}`

  - `ID string`

    Unique identifier for the message

  - `ChatID string`

    ID of the chat this message belongs to

  - `CreatedAt Time`

    When the message was created

  - `DeliveryStatus MessageDeliveryStatus`

    Current delivery status of a message

    - `const MessageDeliveryStatusPending MessageDeliveryStatus = "pending"`

    - `const MessageDeliveryStatusQueued MessageDeliveryStatus = "queued"`

    - `const MessageDeliveryStatusSent MessageDeliveryStatus = "sent"`

    - `const MessageDeliveryStatusDelivered MessageDeliveryStatus = "delivered"`

    - `const MessageDeliveryStatusReceived MessageDeliveryStatus = "received"`

    - `const MessageDeliveryStatusRead MessageDeliveryStatus = "read"`

    - `const MessageDeliveryStatusFailed MessageDeliveryStatus = "failed"`

  - `IsDelivered bool`

    DEPRECATED: Use `delivery_status` instead (true when `delivery_status` is `delivered` or `read`). Whether the message has been delivered.

  - `IsFromMe bool`

    Whether this message was sent by the authenticated user

  - `IsRead bool`

    DEPRECATED: Use `delivery_status == "read"` instead. Whether the message has been read.

  - `UpdatedAt Time`

    When the message was last updated

  - `DeliveredAt Time`

    When the message was delivered

  - `Effect MessageEffect`

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

    - `Name string`

      Name of the effect. Common values:

      - Screen effects: confetti, fireworks, lasers, sparkles, celebration, hearts, love, balloons, happy_birthday, echo, spotlight
      - Bubble effects: slam, loud, gentle, invisible

    - `Type MessageEffectType`

      Type of effect

      - `const MessageEffectTypeScreen MessageEffectType = "screen"`

      - `const MessageEffectTypeBubble MessageEffectType = "bubble"`

  - `From string`

    DEPRECATED: Use from_handle instead. Phone number of the message sender.

  - `FromHandle ChatHandle`

    The sender of this message as a full handle object

    - `ID string`

      Unique identifier for this handle

    - `Handle string`

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

    - `JoinedAt Time`

      When this participant joined the chat

    - `Service ServiceType`

      Messaging service type

      - `const ServiceTypeIMessage ServiceType = "iMessage"`

      - `const ServiceTypeSMS ServiceType = "SMS"`

      - `const ServiceTypeRCS ServiceType = "RCS"`

    - `IsMe bool`

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

    - `LeftAt Time`

      When they left (if applicable)

    - `Status ChatHandleStatus`

      Participant status

      - `const ChatHandleStatusActive ChatHandleStatus = "active"`

      - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

      - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

  - `Parts []MessagePartUnion`

    Message parts in order (text, media, and link)

    - `type TextPartResponse struct{…}`

      A text message part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

          - `const ReactionTypeLove ReactionType = "love"`

          - `const ReactionTypeLike ReactionType = "like"`

          - `const ReactionTypeDislike ReactionType = "dislike"`

          - `const ReactionTypeLaugh ReactionType = "laugh"`

          - `const ReactionTypeEmphasize ReactionType = "emphasize"`

          - `const ReactionTypeQuestion ReactionType = "question"`

          - `const ReactionTypeCustom ReactionType = "custom"`

          - `const ReactionTypeSticker ReactionType = "sticker"`

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

          - `FileName string`

            Filename of the sticker

          - `Height int64`

            Sticker image height in pixels

          - `MimeType string`

            MIME type of the sticker image

          - `URL string`

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

          - `Width int64`

            Sticker image width in pixels

      - `Type TextPartResponseType`

        Indicates this is a text message part

        - `const TextPartResponseTypeText TextPartResponseType = "text"`

      - `Value string`

        The text content

      - `Mention string`

        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.

      - `MentionRange []int64`

        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 []TextPartResponseMention`

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

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

        - `IsMe bool`

          Whether the mentioned participant is this line.

        - `Range []int64`

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

      - `TextDecorations []TextDecoration`

        Text decorations applied to character ranges in the value

        - `Range []int64`

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

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

          - `const TextDecorationAnimationBig TextDecorationAnimation = "big"`

          - `const TextDecorationAnimationSmall TextDecorationAnimation = "small"`

          - `const TextDecorationAnimationShake TextDecorationAnimation = "shake"`

          - `const TextDecorationAnimationNod TextDecorationAnimation = "nod"`

          - `const TextDecorationAnimationExplode TextDecorationAnimation = "explode"`

          - `const TextDecorationAnimationRipple TextDecorationAnimation = "ripple"`

          - `const TextDecorationAnimationBloom TextDecorationAnimation = "bloom"`

          - `const TextDecorationAnimationJitter TextDecorationAnimation = "jitter"`

        - `Style TextDecorationStyle`

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

          - `const TextDecorationStyleBold TextDecorationStyle = "bold"`

          - `const TextDecorationStyleItalic TextDecorationStyle = "italic"`

          - `const TextDecorationStyleStrikethrough TextDecorationStyle = "strikethrough"`

          - `const TextDecorationStyleUnderline TextDecorationStyle = "underline"`

    - `type MediaPartResponse struct{…}`

      A media attachment part

      - `ID string`

        Unique attachment identifier

      - `Filename string`

        Original filename

      - `MimeType string`

        MIME type of the file

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `SizeBytes int64`

        File size in bytes

      - `Type MediaPartResponseType`

        Indicates this is a media attachment part

        - `const MediaPartResponseTypeMedia MediaPartResponseType = "media"`

      - `URL string`

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

    - `type LinkPartResponse struct{…}`

      A rich link preview part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type LinkPartResponseType`

        Indicates this is a rich link preview part

        - `const LinkPartResponseTypeLink LinkPartResponseType = "link"`

      - `Value string`

        The URL

    - `type MessagePartIMessageAppPartResponse struct{…}`

      An iMessage app card part.

      - `App MessagePartIMessageAppPartResponseApp`

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

        - `BundleID string`

          Bundle identifier of the Messages app extension. Must not contain `:`.

        - `Name string`

          Display name of the app, shown by Messages' fallback UI.

        - `TeamID string`

          The app's 10-character uppercase alphanumeric team identifier.

        - `AppStoreID int64`

          The owning app's App Store id (optional). When set, recipients without the iMessage app
          installed see a "Get the app" affordance.

      - `Layout MessagePartIMessageAppPartResponseLayout`

        Visible layout of the card. At least one of
        `caption`, `subcaption`, `trailing_caption`, `trailing_subcaption`, or `image_url` must be
        set, otherwise the card renders as an empty bubble.

        `image_url` displays a preview image at the top of the card. The image renders on the
        recipient's card whether or not they have your app installed. The small icon beside the
        caption is the app's own icon and is not settable here.

        `* Note - requires a trusted chat w/ inbound activity`

        `image_title` and `image_subtitle` render as text overlaid on the image (title bold, subtitle
        beneath it). They only appear when `image_url` is set — without an image there is nothing to
        overlay — so setting either without `image_url` is rejected.

        - `Caption string`

          Primary label, top-left and bold.

        - `ImageSubtitle string`

          Text shown below `image_title`, overlaid on the card image. Requires `image_url`.

        - `ImageTitle string`

          Bold text overlaid on the card image. Requires `image_url` (rejected without it).

        - `ImageURL string`

          URL of an image (JPEG, PNG, HEIF, or WebP) to display as the card's preview image; an unreachable or non-image URL returns a validation error. Renders for all recipients regardless of whether they have the app. Note - requires a trusted chat w/ inbound activity. In responses, this is the re-hosted `cdn.linqapp.com` copy of the image you supplied, not your original URL.

        - `Subcaption string`

          Secondary label, below `caption` on the left.

        - `TrailingCaption string`

          Label shown top-right.

        - `TrailingSubcaption string`

          Label shown below `trailing_caption`, on the right.

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an iMessage app card part.

        - `const MessagePartIMessageAppPartResponseTypeIMessageApp MessagePartIMessageAppPartResponseType = "imessage_app"`

      - `URL string`

        The URL delivered to the iMessage app on tap.

      - `FallbackText string`

        Fallback text for surfaces that cannot render the card.

    - `type MessagePartAppClipPartResponse struct{…}`

      An App Clip card part

      - `Reactions []Reaction`

        Reactions on this message part

        - `Handle ChatHandle`

        - `IsMe bool`

          Whether this reaction is from the current user

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

        - `ID string`

          Identifier for this reaction. Pass it to
          `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

          Stickers placed before this API shipped can be read but not moved: the
          device-side reference needed to reposition them was never recorded, so
          `PATCH` returns 404 for those.

        - `CustomEmoji string`

          Custom emoji if type is "custom", null otherwise

        - `Sticker ReactionSticker`

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

      - `Type string`

        Indicates this is an App Clip card part

        - `const MessagePartAppClipPartResponseTypeAppClip MessagePartAppClipPartResponseType = "app_clip"`

      - `Value string`

        The App Clip link the card opens

      - `Description string`

        The card's summary line, composed by Linq from the App Clip page

      - `ImageURL string`

        The card's preview image

      - `Title string`

        The card's headline, composed by Linq from the App Clip page

  - `PreferredService ServiceType`

    Messaging service type

  - `ReadAt Time`

    When the message was read

  - `ReconciledAt Time`

    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 — the message is genuine but was ingested late, so it may not have appeared in earlier reads of this conversation.

  - `ReplyTo ReplyTo`

    Indicates this message is a threaded reply to another message

    - `MessageID string`

      The ID of the message to reply to

    - `PartIndex int64`

      The specific message part to reply to (0-based index).
      Defaults to 0 (first part) if not provided.
      Use this when replying to a specific part of a multipart message.

  - `SentAt Time`

    When the message was sent

  - `Service ServiceType`

    Messaging service type

### Message Effect

- `type MessageEffect struct{…}`

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

  - `Name string`

    Name of the effect. Common values:

    - Screen effects: confetti, fireworks, lasers, sparkles, celebration, hearts, love, balloons, happy_birthday, echo, spotlight
    - Bubble effects: slam, loud, gentle, invisible

  - `Type MessageEffectType`

    Type of effect

    - `const MessageEffectTypeScreen MessageEffectType = "screen"`

    - `const MessageEffectTypeBubble MessageEffectType = "bubble"`

### Reply To

- `type ReplyTo struct{…}`

  Indicates this message is a threaded reply to another message

  - `MessageID string`

    The ID of the message to reply to

  - `PartIndex int64`

    The specific message part to reply to (0-based index).
    Defaults to 0 (first part) if not provided.
    Use this when replying to a specific part of a multipart message.

# Poll

## Get a poll's current tally

`client.Messages.Poll.Get(ctx, messageID) (*PollEnvelope, error)`

**get** `/v3/messages/{messageId}/poll`

Return a poll's current results — its options, each option's voters, and the distinct
total number of voters — by the poll-definition message's ID.

### Parameters

- `messageID string`

### Returns

- `type PollEnvelope struct{…}`

  Message-level envelope returned by every poll endpoint.

  - `ChatID string`

  - `CreatedAt Time`

  - `MessageID string`

    The poll-definition message's ID — reference this poll by it.

  - `Poll Poll`

    Poll content — options and the aggregate voter count.

    - `Options []PollOption`

      - `CanBeEdited bool`

      - `CreatorHandle ChatHandle`

        The participant who added this option (poll creator for the initial options; whoever added later ones).

        - `ID string`

          Unique identifier for this handle

        - `Handle string`

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

        - `JoinedAt Time`

          When this participant joined the chat

        - `Service ServiceType`

          Messaging service type

          - `const ServiceTypeIMessage ServiceType = "iMessage"`

          - `const ServiceTypeSMS ServiceType = "SMS"`

          - `const ServiceTypeRCS ServiceType = "RCS"`

        - `IsMe bool`

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

        - `LeftAt Time`

          When they left (if applicable)

        - `Status ChatHandleStatus`

          Participant status

          - `const ChatHandleStatusActive ChatHandleStatus = "active"`

          - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

          - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

      - `OptionID string`

      - `Text string`

      - `Voters []PollOptionVoter`

        Participants who voted for this option (vote_count = voters.length).

        - `Handle string`

        - `VotedAt Time`

    - `TotalVoters int64`

      Distinct participants across the whole poll (a voter picking two options counts once).

  - `Reactions []Reaction`

    Tapbacks/stickers on the whole poll (message part 0).

    - `Handle ChatHandle`

    - `IsMe bool`

      Whether this reaction is from the current user

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

      - `const ReactionTypeLove ReactionType = "love"`

      - `const ReactionTypeLike ReactionType = "like"`

      - `const ReactionTypeDislike ReactionType = "dislike"`

      - `const ReactionTypeLaugh ReactionType = "laugh"`

      - `const ReactionTypeEmphasize ReactionType = "emphasize"`

      - `const ReactionTypeQuestion ReactionType = "question"`

      - `const ReactionTypeCustom ReactionType = "custom"`

      - `const ReactionTypeSticker ReactionType = "sticker"`

    - `ID string`

      Identifier for this reaction. Pass it to
      `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

      Stickers placed before this API shipped can be read but not moved: the
      device-side reference needed to reposition them was never recorded, so
      `PATCH` returns 404 for those.

    - `CustomEmoji string`

      Custom emoji if type is "custom", null otherwise

    - `Sticker ReactionSticker`

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

      - `FileName string`

        Filename of the sticker

      - `Height int64`

        Sticker image height in pixels

      - `MimeType string`

        MIME type of the sticker image

      - `URL string`

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

      - `Width int64`

        Sticker image width in pixels

  - `UpdatedAt Time`

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  pollEnvelope, err := client.Messages.Poll.Get(context.TODO(), "69a37c7d-af4f-4b5e-af42-e28e98ce873a")
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", pollEnvelope.ChatID)
}
```

#### Response

```json
{
  "chat_id": "550e8400-e29b-41d4-a716-446655440000",
  "created_at": "2019-12-27T18:11:19.117Z",
  "message_id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
  "poll": {
    "options": [
      {
        "can_be_edited": true,
        "creator_handle": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "handle": "+15551234567",
          "joined_at": "2025-05-21T15:30:00.000-05:00",
          "service": "iMessage",
          "is_me": false,
          "left_at": "2019-12-27T18:11:19.117Z",
          "status": "active"
        },
        "option_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
        "text": "Tacos",
        "voters": [
          {
            "handle": "+14155559876",
            "voted_at": "2019-12-27T18:11:19.117Z"
          }
        ]
      }
    ],
    "total_voters": 0
  },
  "reactions": [
    {
      "handle": {
        "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
        "handle": "+15551234567",
        "joined_at": "2025-05-21T15:30:00.000-05:00",
        "service": "iMessage",
        "is_me": false,
        "left_at": "2019-12-27T18:11:19.117Z",
        "status": "active"
      },
      "is_me": false,
      "type": "love",
      "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
      "custom_emoji": null,
      "sticker": {
        "file_name": "sticker.png",
        "height": 420,
        "mime_type": "image/png",
        "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
        "width": 420
      }
    }
  ],
  "updated_at": "2019-12-27T18:11:19.117Z"
}
```

## Add options to a poll

`client.Messages.Poll.AddOptions(ctx, messageID, body) (*PollEnvelope, error)`

**post** `/v3/messages/{messageId}/poll/options`

Add one or more options to an existing poll. Options are **add-only and immutable** — you
can append options but never edit or remove them (Apple constraint). Returns the full poll.

**On a zero-day-retention line, `options` must include every existing option (in the order
they were originally created) followed by the new one(s)**, not just the new option(s).
Zero-day-retention polls never store option text, so this request is the only place that
text still exists — it's required to correctly render the poll's existing options on the
recipient's device when the update is sent. Omitting an existing option returns `400`.

### Parameters

- `messageID string`

- `body MessagePollAddOptionsParams`

  - `Options param.Field[[]MessagePollAddOptionsParamsOption]`

    - `Text string`

### Returns

- `type PollEnvelope struct{…}`

  Message-level envelope returned by every poll endpoint.

  - `ChatID string`

  - `CreatedAt Time`

  - `MessageID string`

    The poll-definition message's ID — reference this poll by it.

  - `Poll Poll`

    Poll content — options and the aggregate voter count.

    - `Options []PollOption`

      - `CanBeEdited bool`

      - `CreatorHandle ChatHandle`

        The participant who added this option (poll creator for the initial options; whoever added later ones).

        - `ID string`

          Unique identifier for this handle

        - `Handle string`

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

        - `JoinedAt Time`

          When this participant joined the chat

        - `Service ServiceType`

          Messaging service type

          - `const ServiceTypeIMessage ServiceType = "iMessage"`

          - `const ServiceTypeSMS ServiceType = "SMS"`

          - `const ServiceTypeRCS ServiceType = "RCS"`

        - `IsMe bool`

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

        - `LeftAt Time`

          When they left (if applicable)

        - `Status ChatHandleStatus`

          Participant status

          - `const ChatHandleStatusActive ChatHandleStatus = "active"`

          - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

          - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

      - `OptionID string`

      - `Text string`

      - `Voters []PollOptionVoter`

        Participants who voted for this option (vote_count = voters.length).

        - `Handle string`

        - `VotedAt Time`

    - `TotalVoters int64`

      Distinct participants across the whole poll (a voter picking two options counts once).

  - `Reactions []Reaction`

    Tapbacks/stickers on the whole poll (message part 0).

    - `Handle ChatHandle`

    - `IsMe bool`

      Whether this reaction is from the current user

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

      - `const ReactionTypeLove ReactionType = "love"`

      - `const ReactionTypeLike ReactionType = "like"`

      - `const ReactionTypeDislike ReactionType = "dislike"`

      - `const ReactionTypeLaugh ReactionType = "laugh"`

      - `const ReactionTypeEmphasize ReactionType = "emphasize"`

      - `const ReactionTypeQuestion ReactionType = "question"`

      - `const ReactionTypeCustom ReactionType = "custom"`

      - `const ReactionTypeSticker ReactionType = "sticker"`

    - `ID string`

      Identifier for this reaction. Pass it to
      `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

      Stickers placed before this API shipped can be read but not moved: the
      device-side reference needed to reposition them was never recorded, so
      `PATCH` returns 404 for those.

    - `CustomEmoji string`

      Custom emoji if type is "custom", null otherwise

    - `Sticker ReactionSticker`

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

      - `FileName string`

        Filename of the sticker

      - `Height int64`

        Sticker image height in pixels

      - `MimeType string`

        MIME type of the sticker image

      - `URL string`

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

      - `Width int64`

        Sticker image width in pixels

  - `UpdatedAt Time`

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  pollEnvelope, err := client.Messages.Poll.AddOptions(
    context.TODO(),
    "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    linqgo.MessagePollAddOptionsParams{
      Options: []linqgo.MessagePollAddOptionsParamsOption{linqgo.MessagePollAddOptionsParamsOption{
        Text: "Pizza",
      }},
    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", pollEnvelope.ChatID)
}
```

#### Response

```json
{
  "chat_id": "550e8400-e29b-41d4-a716-446655440000",
  "created_at": "2019-12-27T18:11:19.117Z",
  "message_id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
  "poll": {
    "options": [
      {
        "can_be_edited": true,
        "creator_handle": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "handle": "+15551234567",
          "joined_at": "2025-05-21T15:30:00.000-05:00",
          "service": "iMessage",
          "is_me": false,
          "left_at": "2019-12-27T18:11:19.117Z",
          "status": "active"
        },
        "option_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
        "text": "Tacos",
        "voters": [
          {
            "handle": "+14155559876",
            "voted_at": "2019-12-27T18:11:19.117Z"
          }
        ]
      }
    ],
    "total_voters": 0
  },
  "reactions": [
    {
      "handle": {
        "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
        "handle": "+15551234567",
        "joined_at": "2025-05-21T15:30:00.000-05:00",
        "service": "iMessage",
        "is_me": false,
        "left_at": "2019-12-27T18:11:19.117Z",
        "status": "active"
      },
      "is_me": false,
      "type": "love",
      "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
      "custom_emoji": null,
      "sticker": {
        "file_name": "sticker.png",
        "height": 420,
        "mime_type": "image/png",
        "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
        "width": 420
      }
    }
  ],
  "updated_at": "2019-12-27T18:11:19.117Z"
}
```

## Toggle a vote on a poll option

`client.Messages.Poll.Vote(ctx, messageID, body) (*PollEnvelope, error)`

**post** `/v3/messages/{messageId}/poll/votes`

Add or remove your line's vote on **one** poll option (per-option toggle — iMessage polls
are toggled one option at a time). Returns the poll reflecting the toggle.

### Parameters

- `messageID string`

- `body MessagePollVoteParams`

  - `Operation param.Field[MessagePollVoteParamsOperation]`

    Add or remove your line's vote on the option.

    - `const MessagePollVoteParamsOperationAdd MessagePollVoteParamsOperation = "add"`

    - `const MessagePollVoteParamsOperationRemove MessagePollVoteParamsOperation = "remove"`

  - `OptionID param.Field[string]`

    The option to toggle a vote on.

### Returns

- `type PollEnvelope struct{…}`

  Message-level envelope returned by every poll endpoint.

  - `ChatID string`

  - `CreatedAt Time`

  - `MessageID string`

    The poll-definition message's ID — reference this poll by it.

  - `Poll Poll`

    Poll content — options and the aggregate voter count.

    - `Options []PollOption`

      - `CanBeEdited bool`

      - `CreatorHandle ChatHandle`

        The participant who added this option (poll creator for the initial options; whoever added later ones).

        - `ID string`

          Unique identifier for this handle

        - `Handle string`

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

        - `JoinedAt Time`

          When this participant joined the chat

        - `Service ServiceType`

          Messaging service type

          - `const ServiceTypeIMessage ServiceType = "iMessage"`

          - `const ServiceTypeSMS ServiceType = "SMS"`

          - `const ServiceTypeRCS ServiceType = "RCS"`

        - `IsMe bool`

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

        - `LeftAt Time`

          When they left (if applicable)

        - `Status ChatHandleStatus`

          Participant status

          - `const ChatHandleStatusActive ChatHandleStatus = "active"`

          - `const ChatHandleStatusLeft ChatHandleStatus = "left"`

          - `const ChatHandleStatusRemoved ChatHandleStatus = "removed"`

      - `OptionID string`

      - `Text string`

      - `Voters []PollOptionVoter`

        Participants who voted for this option (vote_count = voters.length).

        - `Handle string`

        - `VotedAt Time`

    - `TotalVoters int64`

      Distinct participants across the whole poll (a voter picking two options counts once).

  - `Reactions []Reaction`

    Tapbacks/stickers on the whole poll (message part 0).

    - `Handle ChatHandle`

    - `IsMe bool`

      Whether this reaction is from the current user

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

      - `const ReactionTypeLove ReactionType = "love"`

      - `const ReactionTypeLike ReactionType = "like"`

      - `const ReactionTypeDislike ReactionType = "dislike"`

      - `const ReactionTypeLaugh ReactionType = "laugh"`

      - `const ReactionTypeEmphasize ReactionType = "emphasize"`

      - `const ReactionTypeQuestion ReactionType = "question"`

      - `const ReactionTypeCustom ReactionType = "custom"`

      - `const ReactionTypeSticker ReactionType = "sticker"`

    - `ID string`

      Identifier for this reaction. Pass it to
      `PATCH /v3/messages/{messageId}/reactions/{reactionId}` to move a sticker.

      Stickers placed before this API shipped can be read but not moved: the
      device-side reference needed to reposition them was never recorded, so
      `PATCH` returns 404 for those.

    - `CustomEmoji string`

      Custom emoji if type is "custom", null otherwise

    - `Sticker ReactionSticker`

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

      - `FileName string`

        Filename of the sticker

      - `Height int64`

        Sticker image height in pixels

      - `MimeType string`

        MIME type of the sticker image

      - `URL string`

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

      - `Width int64`

        Sticker image width in pixels

  - `UpdatedAt Time`

### Example

```go
package main

import (
  "context"
  "fmt"

  "github.com/linq-team/linq-go"
  "github.com/linq-team/linq-go/option"
)

func main() {
  client := linqgo.NewClient(
    option.WithAPIKey("My API Key"),
  )
  pollEnvelope, err := client.Messages.Poll.Vote(
    context.TODO(),
    "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
    linqgo.MessagePollVoteParams{
      Operation: linqgo.MessagePollVoteParamsOperationAdd,
      OptionID: "97ce8c17-7ef6-4bbc-a89a-6b93d189712f",
    },
  )
  if err != nil {
    panic(err.Error())
  }
  fmt.Printf("%+v\n", pollEnvelope.ChatID)
}
```

#### Response

```json
{
  "chat_id": "550e8400-e29b-41d4-a716-446655440000",
  "created_at": "2019-12-27T18:11:19.117Z",
  "message_id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
  "poll": {
    "options": [
      {
        "can_be_edited": true,
        "creator_handle": {
          "id": "550e8400-e29b-41d4-a716-446655440000",
          "handle": "+15551234567",
          "joined_at": "2025-05-21T15:30:00.000-05:00",
          "service": "iMessage",
          "is_me": false,
          "left_at": "2019-12-27T18:11:19.117Z",
          "status": "active"
        },
        "option_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
        "text": "Tacos",
        "voters": [
          {
            "handle": "+14155559876",
            "voted_at": "2019-12-27T18:11:19.117Z"
          }
        ]
      }
    ],
    "total_voters": 0
  },
  "reactions": [
    {
      "handle": {
        "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
        "handle": "+15551234567",
        "joined_at": "2025-05-21T15:30:00.000-05:00",
        "service": "iMessage",
        "is_me": false,
        "left_at": "2019-12-27T18:11:19.117Z",
        "status": "active"
      },
      "is_me": false,
      "type": "love",
      "id": "9f8b1c2d-3e4f-5061-7283-94a5b6c7d8e9",
      "custom_emoji": null,
      "sticker": {
        "file_name": "sticker.png",
        "height": 420,
        "mime_type": "image/png",
        "url": "https://cdn.linqapp.com/attachments/a1b2c3d4/sticker.png?signature=...",
        "width": 420
      }
    }
  ],
  "updated_at": "2019-12-27T18:11:19.117Z"
}
```
