## Update an iMessage app card in place

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

### Path Parameters

- `messageId: string`

### Body Parameters

- `layout: object { caption, subcaption, trailing_caption, trailing_subcaption }`

  Visible layout of the card. At least one of
  `caption`, `subcaption`, `trailing_caption`, or `trailing_subcaption` must be set, otherwise
  the card renders as an empty bubble. These four caption fields are the complete set of
  layout properties.

  The `image`, `mediaFileURL`, `imageTitle`, and `imageSubtitle` fields belong to your app's
  own Messages extension, not this API: they only render when an app composes the message
  on-device, and cannot be set here (a sender-supplied image, even delivered as an attachment,
  does not render). The small icon beside the caption is likewise the app's own icon, not a
  settable field.

  - `caption: optional string`

    Primary label, top-left and bold.

  - `subcaption: optional string`

    Secondary label, below `caption` on the left.

  - `trailing_caption: optional string`

    Label shown top-right.

  - `trailing_subcaption: optional string`

    Label shown below `trailing_caption`, on the right.

- `fallback_text: optional string`

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

- `interactive: optional boolean`

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

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

### Returns

- `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" or "queued" or "sent" or 4 more`

    Current delivery status of a message

    - `"pending"`

    - `"queued"`

    - `"sent"`

    - `"delivered"`

    - `"received"`

    - `"read"`

    - `"failed"`

  - `is_read: boolean`

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

  - `parts: array of TextPartResponse or MediaPartResponse or LinkPartResponse or object { app, layout, reactions, 3 more }`

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

    - `TextPartResponse object { reactions, type, value, text_decorations }`

      A text message part

      - `reactions: array of 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

          - `joined_at: string`

            When this participant joined the chat

          - `service: ServiceType`

            Messaging service type

            - `"iMessage"`

            - `"SMS"`

            - `"RCS"`

          - `is_me: optional boolean`

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

          - `left_at: optional string`

            When they left (if applicable)

          - `status: optional "active" or "left" or "removed"`

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

          Custom emoji if type is "custom", null otherwise

        - `sticker: optional object { file_name, height, mime_type, 2 more }`

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

          - `file_name: optional string`

            Filename of the sticker

          - `height: optional number`

            Sticker image height in pixels

          - `mime_type: optional string`

            MIME type of the sticker image

          - `url: optional string`

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

          - `width: optional number`

            Sticker image width in pixels

      - `type: "text"`

        Indicates this is a text message part

        - `"text"`

      - `value: string`

        The text content

      - `text_decorations: optional array of TextDecoration`

        Text decorations applied to character ranges in the value

        - `range: array of 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: optional "big" or "small" or "shake" or 5 more`

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

          - `"big"`

          - `"small"`

          - `"shake"`

          - `"nod"`

          - `"explode"`

          - `"ripple"`

          - `"bloom"`

          - `"jitter"`

        - `style: optional "bold" or "italic" or "strikethrough" or "underline"`

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

          - `"bold"`

          - `"italic"`

          - `"strikethrough"`

          - `"underline"`

    - `MediaPartResponse object { id, filename, mime_type, 4 more }`

      A media attachment part

      - `id: string`

        Unique attachment identifier

      - `filename: string`

        Original filename

      - `mime_type: string`

        MIME type of the file

      - `reactions: array of Reaction`

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

          Custom emoji if type is "custom", null otherwise

        - `sticker: optional object { file_name, height, mime_type, 2 more }`

          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 object { reactions, type, value }`

      A rich link preview part

      - `reactions: array of Reaction`

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

          Custom emoji if type is "custom", null otherwise

        - `sticker: optional object { file_name, height, mime_type, 2 more }`

          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

    - `IMessageAppPartResponse object { app, layout, reactions, 3 more }`

      An iMessage app card part.

      - `app: object { bundle_id, name, team_id, app_store_id }`

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

        - `bundle_id: string`

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

        - `name: string`

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

        - `team_id: string`

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

        - `app_store_id: optional number`

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

      - `layout: object { caption, subcaption, trailing_caption, trailing_subcaption }`

        Visible layout of the card. At least one of
        `caption`, `subcaption`, `trailing_caption`, or `trailing_subcaption` must be set, otherwise
        the card renders as an empty bubble. These four caption fields are the complete set of
        layout properties.

        The `image`, `mediaFileURL`, `imageTitle`, and `imageSubtitle` fields belong to your app's
        own Messages extension, not this API: they only render when an app composes the message
        on-device, and cannot be set here (a sender-supplied image, even delivered as an attachment,
        does not render). The small icon beside the caption is likewise the app's own icon, not a
        settable field.

        - `caption: optional string`

          Primary label, top-left and bold.

        - `subcaption: optional string`

          Secondary label, below `caption` on the left.

        - `trailing_caption: optional string`

          Label shown top-right.

        - `trailing_subcaption: optional string`

          Label shown below `trailing_caption`, on the right.

      - `reactions: array of Reaction`

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

          Custom emoji if type is "custom", null otherwise

        - `sticker: optional object { file_name, height, mime_type, 2 more }`

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

      - `type: "imessage_app"`

        Indicates this is an iMessage app card part.

        - `"imessage_app"`

      - `url: string`

        The URL delivered to the iMessage app on tap.

      - `fallback_text: optional string`

        Fallback text for surfaces that cannot render the card.

  - `sent_at: string`

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

  - `delivered_at: optional string`

    When the message was delivered

  - `effect: optional MessageEffect`

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

    - `name: optional 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: optional "screen" or "bubble"`

      Type of effect

      - `"screen"`

      - `"bubble"`

  - `from_handle: optional ChatHandle`

    The sender of this message as a full handle object

  - `preferred_service: optional ServiceType`

    Messaging service type

  - `reply_to: optional ReplyTo`

    Indicates this message is a threaded reply to another message

    - `message_id: string`

      The ID of the message to reply to

    - `part_index: optional 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: optional ServiceType`

    Messaging service type

### Example

```http
curl https://api.linqapp.com/api/partner/v3/messages/$MESSAGE_ID/update \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $LINQ_API_V3_API_KEY" \
    -d '{
          "layout": {
            "caption": "Score: 2 – 1"
          },
          "fallback_text": "Score update",
          "interactive": true,
          "url": "https://app.example.com/card?game=7f3a&move=2"
        }'
```

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