# Messages

## Send a message to an existing chat

`client.chats.messages.send(stringchatID, MessageSendParamsbody, RequestOptionsoptions?): MessageSendResponse`

**post** `/v3/chats/{chatId}/messages`

Send a message to an existing chat. Use this endpoint when you already have
a chat ID and want to send additional messages to it.

## Message Effects

You can add iMessage effects to make your messages more expressive. Effects are
optional and can be either screen effects (full-screen animations) or bubble effects
(message bubble animations).

**Screen Effects:** `confetti`, `fireworks`, `lasers`, `sparkles`, `celebration`,
`hearts`, `love`, `balloons`, `happy_birthday`, `echo`, `spotlight`

**Bubble Effects:** `slam`, `loud`, `gentle`, `invisible`

Only one effect type can be applied per message.

## Inline Text Decorations (iMessage only)

Use the `text_decorations` array on a text part to apply styling and animations to character ranges.

Each decoration specifies a `range: [start, end)` and exactly one of `style` or `animation`.

**Styles:** `bold`, `italic`, `strikethrough`, `underline`
**Animations:** `big`, `small`, `shake`, `nod`, `explode`, `ripple`, `bloom`, `jitter`

```json
{
  "type": "text",
  "value": "Hello world",
  "text_decorations": [
    { "range": [0, 5], "style": "bold" },
    { "range": [6, 11], "animation": "shake" }
  ]
}
```

**Note:** Style ranges (bold, italic, etc.) may overlap, but animation ranges must not overlap with other animations or styles. Text decorations only render for iMessage recipients.
For SMS/RCS, text decorations are not applied.

### Parameters

- `chatID: string`

- `body: MessageSendParams`

  - `message: MessageContent`

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

    - `parts: Array<TextPart | MediaPart | LinkPart>`

      Array of message parts. Each part can be text, media, or link.
      Parts are displayed in order. Text and media can be mixed freely,
      but a `link` part must be the only part in the message.

      **Rich Link Previews:**

      - Use a `link` part to send a URL with a rich preview card
      - A `link` part must be the **only** part in the message
      - To send a URL as plain text (no preview), use a `text` part instead

      **Supported Media:**

      - Images: .jpg, .jpeg, .png, .gif, .heic, .heif, .tif, .tiff, .bmp
      - Videos: .mp4, .mov, .m4v, .mpeg, .mpg, .3gp
      - Audio: .m4a, .mp3, .aac, .caf, .wav, .aiff, .amr
      - Documents: .pdf, .txt, .rtf, .csv, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .pages, .numbers, .key, .epub, .zip, .html, .htm
      - Contact & Calendar: .vcf, .ics

      **Audio:**

      - Audio files (.m4a, .mp3, .aac, .caf, .wav, .aiff, .amr) are fully supported as media parts
      - To send audio as an **iMessage voice memo bubble** (inline playback UI), use the dedicated
        `/v3/chats/{chatId}/voicememo` endpoint instead

      **Validation Rules:**

      - A `link` part must be the **only** part in the message. It cannot be combined
        with text or media parts.
      - Consecutive text parts are not allowed. Text parts must be separated by
        media parts. For example, [text, text] is invalid, but [text, media, text] is valid.
      - Maximum of **100 parts** total.
      - Media parts using a public `url` (downloaded by the server on send) are
        capped at **40**. Parts using `attachment_id` or presigned URLs
        are exempt from this sub-limit. For bulk media sends exceeding 40 files,
        pre-upload via `POST /v3/attachments` and reference by `attachment_id` or `download_url`.

      - `TextPart`

        - `type: "text"`

          Indicates this is a text message part

          - `"text"`

        - `value: string`

          The text content of the message. This value is sent as-is with no parsing or transformation — Markdown syntax will be delivered as plain text. Use `text_decorations` to apply inline formatting and animations (iMessage only).

        - `text_decorations?: Array<TextDecoration>`

          Optional array of text decorations applied to character ranges in the `value` field (iMessage only).

          Each decoration specifies a character range `[start, end)` and exactly one of `style` or `animation`.

          **Styles:** `bold`, `italic`, `strikethrough`, `underline`
          **Animations:** `big`, `small`, `shake`, `nod`, `explode`, `ripple`, `bloom`, `jitter`

          Style ranges may overlap (e.g. bold + italic on the same text), but animation ranges must not overlap with other animations or styles.

          *Characters are measured as UTF-16 code units. Most characters count as 1; some emoji count as 2.*

          **Note:** Text decorations only render for iMessage recipients. For SMS/RCS, text decorations are not applied.

          - `range: Array<number>`

            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?: "big" | "small" | "shake" | 5 more`

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

            - `"big"`

            - `"small"`

            - `"shake"`

            - `"nod"`

            - `"explode"`

            - `"ripple"`

            - `"bloom"`

            - `"jitter"`

          - `style?: "bold" | "italic" | "strikethrough" | "underline"`

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

            - `"bold"`

            - `"italic"`

            - `"strikethrough"`

            - `"underline"`

      - `MediaPart`

        - `type: "media"`

          Indicates this is a media attachment part

          - `"media"`

        - `attachment_id?: string`

          Reference to a file pre-uploaded via `POST /v3/attachments` (optional).
          The file is already stored, so sends using this ID skip the download step —
          useful when sending the same file to many recipients.

          Either `url` or `attachment_id` must be provided, but not both.

        - `url?: string`

          Any publicly accessible HTTPS URL to the media file. The server downloads and
          sends the file automatically — no pre-upload step required.

          **Size limit:** 10MB maximum for URL-based downloads. For larger files (up to 100MB),
          use the pre-upload flow: `POST /v3/attachments` to get a presigned URL, upload directly,
          then reference by `attachment_id`.

          **Requirements:**

          - URL must use HTTPS
          - File content must be a supported format (the server validates the actual file content)

          **Supported formats:**

          - Images: .jpg, .jpeg, .png, .gif, .heic, .heif, .tif, .tiff, .bmp
          - Videos: .mp4, .mov, .m4v, .mpeg, .mpg, .3gp
          - Audio: .m4a, .mp3, .aac, .caf, .wav, .aiff, .amr
          - Documents: .pdf, .txt, .rtf, .csv, .doc, .docx, .xls, .xlsx, .ppt, .pptx, .pages, .numbers, .key, .epub, .zip, .html, .htm
          - Contact & Calendar: .vcf, .ics

          **Tip:** Audio sent here appears as a regular file attachment. To send audio as an
          iMessage voice memo bubble (with inline playback), use `/v3/chats/{chatId}/voicememo`.
          For repeated sends of the same file, use `attachment_id` to avoid redundant downloads.

          Either `url` or `attachment_id` must be provided, but not both.

      - `LinkPart`

        - `type: "link"`

          Indicates this is a rich link preview part

          - `"link"`

        - `value: string`

          URL to send with a rich link preview. The recipient will see an inline card
          with the page's title, description, and preview image (when available).

          A `link` part must be the **only** part in the message. To send a URL as plain
          text (no preview card), use a `text` part instead.

    - `effect?: MessageEffect`

      iMessage effect to apply to this 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?: "screen" | "bubble"`

        Type of effect

        - `"screen"`

        - `"bubble"`

    - `idempotency_key?: string`

      Optional idempotency key for this message.
      Use this to prevent duplicate sends of the same message.

    - `preferred_service?: ServiceType`

      Messaging service type

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

    - `reply_to?: ReplyTo`

      Reply to another message to create a threaded conversation

      - `message_id: string`

        The ID of the message to reply to

      - `part_index?: number`

        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.

### Returns

- `MessageSendResponse`

  Response for sending a message to a chat

  - `chat_id: 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)

    - `created_at: string`

      When the message was created

    - `delivery_status: "pending" | "queued" | "sent" | 2 more`

      Current delivery status of a message

      - `"pending"`

      - `"queued"`

      - `"sent"`

      - `"delivered"`

      - `"failed"`

    - `is_read: boolean`

      Whether the message has been read

    - `parts: Array<TextPartResponse | MediaPartResponse | LinkPartResponse>`

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

      - `TextPartResponse`

        A text message part

        - `reactions: Array<Reaction> | null`

          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

            - `joined_at: string`

              When this participant joined the chat

            - `service: ServiceType`

              Messaging service type

              - `"iMessage"`

              - `"SMS"`

              - `"RCS"`

            - `is_me?: boolean | null`

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

            - `left_at?: string | null`

              When they left (if applicable)

            - `status?: "active" | "left" | "removed" | null`

              Participant status

              - `"active"`

              - `"left"`

              - `"removed"`

          - `is_me: boolean`

            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.

            - `"love"`

            - `"like"`

            - `"dislike"`

            - `"laugh"`

            - `"emphasize"`

            - `"question"`

            - `"custom"`

            - `"sticker"`

          - `custom_emoji?: string | null`

            Custom emoji if type is "custom", null otherwise

          - `sticker?: Sticker | null`

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

            - `file_name?: string`

              Filename of the sticker

            - `height?: number`

              Sticker image height in pixels

            - `mime_type?: string`

              MIME type of the sticker image

            - `url?: string`

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

            - `width?: number`

              Sticker image width in pixels

        - `type: "text"`

          Indicates this is a text message part

          - `"text"`

        - `value: string`

          The text content

        - `text_decorations?: Array<TextDecoration> | null`

          Text decorations applied to character ranges in the value

          - `range: Array<number>`

            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?: "big" | "small" | "shake" | 5 more`

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

            - `"big"`

            - `"small"`

            - `"shake"`

            - `"nod"`

            - `"explode"`

            - `"ripple"`

            - `"bloom"`

            - `"jitter"`

          - `style?: "bold" | "italic" | "strikethrough" | "underline"`

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

            - `"bold"`

            - `"italic"`

            - `"strikethrough"`

            - `"underline"`

      - `MediaPartResponse`

        A media attachment part

        - `id: string`

          Unique attachment identifier

        - `filename: string`

          Original filename

        - `mime_type: string`

          MIME type of the file

        - `reactions: Array<Reaction> | null`

          Reactions on this message part

          - `handle: ChatHandle`

          - `is_me: boolean`

            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.

          - `custom_emoji?: string | null`

            Custom emoji if type is "custom", null otherwise

          - `sticker?: Sticker | null`

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

        - `size_bytes: number`

          File size in bytes

        - `type: "media"`

          Indicates this is a media attachment part

          - `"media"`

        - `url: string`

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

      - `LinkPartResponse`

        A rich link preview part

        - `reactions: Array<Reaction> | null`

          Reactions on this message part

          - `handle: ChatHandle`

          - `is_me: boolean`

            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.

          - `custom_emoji?: string | null`

            Custom emoji if type is "custom", null otherwise

          - `sticker?: Sticker | null`

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

        - `type: "link"`

          Indicates this is a rich link preview part

          - `"link"`

        - `value: string`

          The URL

    - `sent_at: string | null`

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

    - `delivered_at?: string | null`

      When the message was delivered

    - `effect?: MessageEffect | null`

      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?: "screen" | "bubble"`

        Type of effect

        - `"screen"`

        - `"bubble"`

    - `from_handle?: ChatHandle | null`

      The sender of this message as a full handle object

    - `preferred_service?: ServiceType | null`

      Messaging service type

    - `reply_to?: ReplyTo | null`

      Indicates this message is a threaded reply to another message

      - `message_id: string`

        The ID of the message to reply to

      - `part_index?: number`

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

      Messaging service type

### Example

```typescript
import LinqAPIV3 from '@linqapp/sdk';

const client = new LinqAPIV3({
  apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted
});

const response = await client.chats.messages.send('550e8400-e29b-41d4-a716-446655440000', {
  message: { parts: [{ type: 'text', value: 'Hello, world!' }] },
});

console.log(response.chat_id);
```

#### 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",
            "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!",
        "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"
  }
}
```

## Get messages from a chat

`client.chats.messages.list(stringchatID, MessageListParamsquery?, RequestOptionsoptions?): ListMessagesPagination<Message>`

**get** `/v3/chats/{chatId}/messages`

Retrieve messages from a specific chat with pagination support.

### Parameters

- `chatID: string`

- `query: MessageListParams`

  - `cursor?: string`

    Pagination cursor from previous next_cursor response

  - `limit?: number`

    Maximum number of messages to return

### Returns

- `Message`

  - `id: string`

    Unique identifier for the message

  - `chat_id: string`

    ID of the chat this message belongs to

  - `created_at: string`

    When the message was created

  - `is_delivered: boolean`

    Whether the message has been delivered

  - `is_from_me: boolean`

    Whether this message was sent by the authenticated user

  - `is_read: boolean`

    Whether the message has been read

  - `updated_at: string`

    When the message was last updated

  - `delivered_at?: string | null`

    When the message was delivered

  - `effect?: MessageEffect | null`

    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?: "screen" | "bubble"`

      Type of effect

      - `"screen"`

      - `"bubble"`

  - `from?: string | null`

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

  - `from_handle?: ChatHandle | null`

    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

    - `joined_at: string`

      When this participant joined the chat

    - `service: ServiceType`

      Messaging service type

      - `"iMessage"`

      - `"SMS"`

      - `"RCS"`

    - `is_me?: boolean | null`

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

    - `left_at?: string | null`

      When they left (if applicable)

    - `status?: "active" | "left" | "removed" | null`

      Participant status

      - `"active"`

      - `"left"`

      - `"removed"`

  - `parts?: Array<TextPartResponse | MediaPartResponse | LinkPartResponse> | null`

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

    - `TextPartResponse`

      A text message part

      - `reactions: Array<Reaction> | null`

        Reactions on this message part

        - `handle: ChatHandle`

        - `is_me: boolean`

          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.

          - `"love"`

          - `"like"`

          - `"dislike"`

          - `"laugh"`

          - `"emphasize"`

          - `"question"`

          - `"custom"`

          - `"sticker"`

        - `custom_emoji?: string | null`

          Custom emoji if type is "custom", null otherwise

        - `sticker?: Sticker | null`

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

          - `file_name?: string`

            Filename of the sticker

          - `height?: number`

            Sticker image height in pixels

          - `mime_type?: string`

            MIME type of the sticker image

          - `url?: string`

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

          - `width?: number`

            Sticker image width in pixels

      - `type: "text"`

        Indicates this is a text message part

        - `"text"`

      - `value: string`

        The text content

      - `text_decorations?: Array<TextDecoration> | null`

        Text decorations applied to character ranges in the value

        - `range: Array<number>`

          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?: "big" | "small" | "shake" | 5 more`

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

          - `"big"`

          - `"small"`

          - `"shake"`

          - `"nod"`

          - `"explode"`

          - `"ripple"`

          - `"bloom"`

          - `"jitter"`

        - `style?: "bold" | "italic" | "strikethrough" | "underline"`

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

          - `"bold"`

          - `"italic"`

          - `"strikethrough"`

          - `"underline"`

    - `MediaPartResponse`

      A media attachment part

      - `id: string`

        Unique attachment identifier

      - `filename: string`

        Original filename

      - `mime_type: string`

        MIME type of the file

      - `reactions: Array<Reaction> | null`

        Reactions on this message part

        - `handle: ChatHandle`

        - `is_me: boolean`

          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.

        - `custom_emoji?: string | null`

          Custom emoji if type is "custom", null otherwise

        - `sticker?: Sticker | null`

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

      - `size_bytes: number`

        File size in bytes

      - `type: "media"`

        Indicates this is a media attachment part

        - `"media"`

      - `url: string`

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

    - `LinkPartResponse`

      A rich link preview part

      - `reactions: Array<Reaction> | null`

        Reactions on this message part

        - `handle: ChatHandle`

        - `is_me: boolean`

          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.

        - `custom_emoji?: string | null`

          Custom emoji if type is "custom", null otherwise

        - `sticker?: Sticker | null`

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

      - `type: "link"`

        Indicates this is a rich link preview part

        - `"link"`

      - `value: string`

        The URL

  - `preferred_service?: ServiceType | null`

    Messaging service type

  - `read_at?: string | null`

    When the message was read

  - `reply_to?: ReplyTo | null`

    Indicates this message is a threaded reply to another message

    - `message_id: string`

      The ID of the message to reply to

    - `part_index?: number`

      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.

  - `sent_at?: string | null`

    When the message was sent

  - `service?: ServiceType | null`

    Messaging service type

### Example

```typescript
import LinqAPIV3 from '@linqapp/sdk';

const client = new LinqAPIV3({
  apiKey: process.env['LINQ_API_V3_API_KEY'], // This is the default and can be omitted
});

// Automatically fetches more pages as needed.
for await (const message of client.chats.messages.list('550e8400-e29b-41d4-a716-446655440000')) {
  console.log(message.id);
}
```

#### Response

```json
{
  "messages": [
    {
      "id": "69a37c7d-af4f-4b5e-af42-e28e98ce873a",
      "chat_id": "94c6bf33-31d9-40e3-a0e9-f94250ecedb9",
      "created_at": "2024-01-15T10:30:00Z",
      "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",
              "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!",
          "text_decorations": [
            {
              "range": [
                0,
                5
              ],
              "animation": "shake",
              "style": "bold"
            }
          ]
        }
      ],
      "preferred_service": "iMessage",
      "read_at": "2024-01-15T10:35:00Z",
      "reply_to": {
        "message_id": "550e8400-e29b-41d4-a716-446655440000",
        "part_index": 0
      },
      "sent_at": "2024-01-15T10:30:05Z",
      "service": "iMessage"
    }
  ],
  "next_cursor": "next_cursor"
}
```

## Domain Types

### Sent Message

- `SentMessage`

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

  - `id: string`

    Message identifier (UUID)

  - `created_at: string`

    When the message was created

  - `delivery_status: "pending" | "queued" | "sent" | 2 more`

    Current delivery status of a message

    - `"pending"`

    - `"queued"`

    - `"sent"`

    - `"delivered"`

    - `"failed"`

  - `is_read: boolean`

    Whether the message has been read

  - `parts: Array<TextPartResponse | MediaPartResponse | LinkPartResponse>`

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

    - `TextPartResponse`

      A text message part

      - `reactions: Array<Reaction> | null`

        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

          - `joined_at: string`

            When this participant joined the chat

          - `service: ServiceType`

            Messaging service type

            - `"iMessage"`

            - `"SMS"`

            - `"RCS"`

          - `is_me?: boolean | null`

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

          - `left_at?: string | null`

            When they left (if applicable)

          - `status?: "active" | "left" | "removed" | null`

            Participant status

            - `"active"`

            - `"left"`

            - `"removed"`

        - `is_me: boolean`

          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.

          - `"love"`

          - `"like"`

          - `"dislike"`

          - `"laugh"`

          - `"emphasize"`

          - `"question"`

          - `"custom"`

          - `"sticker"`

        - `custom_emoji?: string | null`

          Custom emoji if type is "custom", null otherwise

        - `sticker?: Sticker | null`

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

          - `file_name?: string`

            Filename of the sticker

          - `height?: number`

            Sticker image height in pixels

          - `mime_type?: string`

            MIME type of the sticker image

          - `url?: string`

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

          - `width?: number`

            Sticker image width in pixels

      - `type: "text"`

        Indicates this is a text message part

        - `"text"`

      - `value: string`

        The text content

      - `text_decorations?: Array<TextDecoration> | null`

        Text decorations applied to character ranges in the value

        - `range: Array<number>`

          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?: "big" | "small" | "shake" | 5 more`

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

          - `"big"`

          - `"small"`

          - `"shake"`

          - `"nod"`

          - `"explode"`

          - `"ripple"`

          - `"bloom"`

          - `"jitter"`

        - `style?: "bold" | "italic" | "strikethrough" | "underline"`

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

          - `"bold"`

          - `"italic"`

          - `"strikethrough"`

          - `"underline"`

    - `MediaPartResponse`

      A media attachment part

      - `id: string`

        Unique attachment identifier

      - `filename: string`

        Original filename

      - `mime_type: string`

        MIME type of the file

      - `reactions: Array<Reaction> | null`

        Reactions on this message part

        - `handle: ChatHandle`

        - `is_me: boolean`

          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.

        - `custom_emoji?: string | null`

          Custom emoji if type is "custom", null otherwise

        - `sticker?: Sticker | null`

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

      - `size_bytes: number`

        File size in bytes

      - `type: "media"`

        Indicates this is a media attachment part

        - `"media"`

      - `url: string`

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

    - `LinkPartResponse`

      A rich link preview part

      - `reactions: Array<Reaction> | null`

        Reactions on this message part

        - `handle: ChatHandle`

        - `is_me: boolean`

          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.

        - `custom_emoji?: string | null`

          Custom emoji if type is "custom", null otherwise

        - `sticker?: Sticker | null`

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

      - `type: "link"`

        Indicates this is a rich link preview part

        - `"link"`

      - `value: string`

        The URL

  - `sent_at: string | null`

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

  - `delivered_at?: string | null`

    When the message was delivered

  - `effect?: MessageEffect | null`

    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?: "screen" | "bubble"`

      Type of effect

      - `"screen"`

      - `"bubble"`

  - `from_handle?: ChatHandle | null`

    The sender of this message as a full handle object

  - `preferred_service?: ServiceType | null`

    Messaging service type

  - `reply_to?: ReplyTo | null`

    Indicates this message is a threaded reply to another message

    - `message_id: string`

      The ID of the message to reply to

    - `part_index?: number`

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

    Messaging service type

### Message Send Response

- `MessageSendResponse`

  Response for sending a message to a chat

  - `chat_id: 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)

    - `created_at: string`

      When the message was created

    - `delivery_status: "pending" | "queued" | "sent" | 2 more`

      Current delivery status of a message

      - `"pending"`

      - `"queued"`

      - `"sent"`

      - `"delivered"`

      - `"failed"`

    - `is_read: boolean`

      Whether the message has been read

    - `parts: Array<TextPartResponse | MediaPartResponse | LinkPartResponse>`

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

      - `TextPartResponse`

        A text message part

        - `reactions: Array<Reaction> | null`

          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

            - `joined_at: string`

              When this participant joined the chat

            - `service: ServiceType`

              Messaging service type

              - `"iMessage"`

              - `"SMS"`

              - `"RCS"`

            - `is_me?: boolean | null`

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

            - `left_at?: string | null`

              When they left (if applicable)

            - `status?: "active" | "left" | "removed" | null`

              Participant status

              - `"active"`

              - `"left"`

              - `"removed"`

          - `is_me: boolean`

            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.

            - `"love"`

            - `"like"`

            - `"dislike"`

            - `"laugh"`

            - `"emphasize"`

            - `"question"`

            - `"custom"`

            - `"sticker"`

          - `custom_emoji?: string | null`

            Custom emoji if type is "custom", null otherwise

          - `sticker?: Sticker | null`

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

            - `file_name?: string`

              Filename of the sticker

            - `height?: number`

              Sticker image height in pixels

            - `mime_type?: string`

              MIME type of the sticker image

            - `url?: string`

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

            - `width?: number`

              Sticker image width in pixels

        - `type: "text"`

          Indicates this is a text message part

          - `"text"`

        - `value: string`

          The text content

        - `text_decorations?: Array<TextDecoration> | null`

          Text decorations applied to character ranges in the value

          - `range: Array<number>`

            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?: "big" | "small" | "shake" | 5 more`

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

            - `"big"`

            - `"small"`

            - `"shake"`

            - `"nod"`

            - `"explode"`

            - `"ripple"`

            - `"bloom"`

            - `"jitter"`

          - `style?: "bold" | "italic" | "strikethrough" | "underline"`

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

            - `"bold"`

            - `"italic"`

            - `"strikethrough"`

            - `"underline"`

      - `MediaPartResponse`

        A media attachment part

        - `id: string`

          Unique attachment identifier

        - `filename: string`

          Original filename

        - `mime_type: string`

          MIME type of the file

        - `reactions: Array<Reaction> | null`

          Reactions on this message part

          - `handle: ChatHandle`

          - `is_me: boolean`

            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.

          - `custom_emoji?: string | null`

            Custom emoji if type is "custom", null otherwise

          - `sticker?: Sticker | null`

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

        - `size_bytes: number`

          File size in bytes

        - `type: "media"`

          Indicates this is a media attachment part

          - `"media"`

        - `url: string`

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

      - `LinkPartResponse`

        A rich link preview part

        - `reactions: Array<Reaction> | null`

          Reactions on this message part

          - `handle: ChatHandle`

          - `is_me: boolean`

            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.

          - `custom_emoji?: string | null`

            Custom emoji if type is "custom", null otherwise

          - `sticker?: Sticker | null`

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

        - `type: "link"`

          Indicates this is a rich link preview part

          - `"link"`

        - `value: string`

          The URL

    - `sent_at: string | null`

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

    - `delivered_at?: string | null`

      When the message was delivered

    - `effect?: MessageEffect | null`

      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?: "screen" | "bubble"`

        Type of effect

        - `"screen"`

        - `"bubble"`

    - `from_handle?: ChatHandle | null`

      The sender of this message as a full handle object

    - `preferred_service?: ServiceType | null`

      Messaging service type

    - `reply_to?: ReplyTo | null`

      Indicates this message is a threaded reply to another message

      - `message_id: string`

        The ID of the message to reply to

      - `part_index?: number`

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

      Messaging service type
