Explore practical payload structures for each message kind supported by the `messaging.send` capability, along with the action types you can attach. Copy these examples and adapt them to your use case.

**Permission:** `messaging:send` in your `manifest.json`. The author label above outbound messages is set **per-Instance by the admin** via the Instance settings field `messagingDisplayName`; falls back to `extension.manifest.name` when blank. Extensions do not set or think about the author identity.

---

## kind: 'text' — Plain text + reply actions

Plain conversational message. Optional `actions` array attaches quick-reply buttons, links, postbacks, or location requests.

```tsx
const [send] = useMessaging()

await send({
  "kind": "text",
  "body": "Order approved ✓",
  "actions": [
    {
      "type": "reply",
      "label": "Got it",
      "payload": "ACK"
    },
    {
      "type": "reply",
      "label": "Show details",
      "payload": "DETAILS"
    }
  ]
})
```

## kind: 'image' — Embedded image + optional caption

Product photos, screenshots, visual help. `url` must respond with a `Content-Type: image/*` header (Sunco enforces; redirecting URLs like `picsum.photos` will fail). `altText` is optional — defaults to filename. Optional `body` renders a caption alongside the image.

```tsx
const [send] = useMessaging()

await send({
  "kind": "image",
  "url": "https://cdn.example.com/products/widget-blue.jpg",
  "altText": "Blue widget — model A24",
  "body": "Here is the product you asked about:",
  "actions": [
    {
      "type": "link",
      "label": "View on site",
      "url": "https://example.com/p/widget-a24"
    }
  ]
})
```

## kind: 'file' — Embedded file attachment

Return labels, receipts, NDAs, warranty paperwork. Sunco's `fileMessage` schema does NOT support `actions` — file messages can only carry an optional text caption.

```tsx
const [send] = useMessaging()

await send({
  "kind": "file",
  "url": "https://cdn.example.com/receipts/order-12345.pdf",
  "altText": "Receipt for order #12345",
  "body": "Your receipt is attached."
})
```

## kind: 'carousel' — Horizontally scrolling cards

The conversational-commerce primitive: product recommendations, size/color pickers, search results with images, multi-option selection.

- 1–10 items, each with required `title` + required `actions` (1–3 per item)
- Item actions are a subset: `link` + `postback` only (no `reply`, no `locationRequest` — Sunco rejects those at the item level)
- Carousel messages have NO message-level `actions` field — actions live per-card
- Use a separate `text` message before the carousel if you need an intro

```tsx
const [send] = useMessaging()

await send({
  "kind": "carousel",
  "items": [
    {
      "title": "Widget A24 — Blue",
      "description": "In stock — ships in 1-2 days",
      "imageUrl": "https://cdn.example.com/products/widget-blue.jpg",
      "actions": [
        {
          "type": "link",
          "label": "View",
          "url": "https://example.com/p/widget-a24-blue"
        },
        {
          "type": "postback",
          "label": "Add to cart",
          "payload": "add_to_cart:widget-a24-blue"
        }
      ]
    },
    {
      "title": "Widget A24 — Red",
      "description": "Limited stock",
      "imageUrl": "https://cdn.example.com/products/widget-red.jpg",
      "actions": [
        {
          "type": "link",
          "label": "View",
          "url": "https://example.com/p/widget-a24-red"
        },
        {
          "type": "postback",
          "label": "Add to cart",
          "payload": "add_to_cart:widget-a24-red"
        }
      ]
    }
  ],
  "displaySettings": {
    "imageAspectRatio": "horizontal"
  }
})
```

---

## Action types

Attach to message-level `actions` (text / image) or item-level `actions` (carousel). All actions share `label` + optional `metadata` (primitives only, ≤4KB total).

### type: 'reply'

Inserts a visible user-reply bubble carrying `payload` back into the conversation, as if the user typed it. **Mutually exclusive** — a `reply` action cannot share an `actions[]` array with any other action type; the host validates and surfaces `invalid_message` if mixed.

```tsx
{
  "type": "reply",
  "label": "Got it",
  "payload": "ACK"
}
```

### type: 'link'

Opens `url` in a new tab/window. No bubble inserted. Freely mixable with other non-reply actions.

```tsx
{
  "type": "link",
  "label": "View on site",
  "url": "https://example.com/p/widget-a24"
}
```

### type: 'postback'

Fires a server-side `conversation:postback` webhook to the Stackable backend carrying the full `payload` + any `metadata`. NO visible bubble. Extensions with the `events:messaging` permission receive postback events via `useMessagingEvent` — see the **Events & Identity** cookbook.

```tsx
{
  "type": "postback",
  "label": "Add to cart",
  "payload": "add_to_cart:widget-a24"
}
```

### type: 'locationRequest'

Prompts the user to share device location. Response arrives as a separate `location`-type message inbound to the conversation. Freely mixable.

```tsx
{
  "type": "locationRequest",
  "label": "Share location"
}
```
