> ## Documentation Index
> Fetch the complete documentation index at: https://botpress-pb-update-api.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Send messages and content

> Send text, images, cards, carousels, and more from your handler.

While `execute()` lets the AI model handle messaging automatically, sometimes you need to send messages directly from your handler. The `conversation.send()` method gives you full control over what gets sent.

## Sending a text message

```typescript theme={null}
await conversation.send({
  type: "text",
  payload: { text: "Hello! How can I help you?" },
})
```

## Message types

The available message types depend on which channel your agent is deployed on. For [Webchat](/webchat/get-started/introduction), the following types are supported:

| Type              | Payload                                     | Description                                                                                                                                                                                    |
| ----------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `text`            | `{ text, value? }`                          | Plain text message                                                                                                                                                                             |
| `markdown`        | `{ markdown }`                              | Markdown-formatted text                                                                                                                                                                        |
| `image`           | `{ imageUrl }`                              | Image from a URL                                                                                                                                                                               |
| `audio`           | `{ audioUrl }`                              | Audio file                                                                                                                                                                                     |
| `video`           | `{ videoUrl }`                              | Video file                                                                                                                                                                                     |
| `file`            | `{ fileUrl, title? }`                       | Downloadable file                                                                                                                                                                              |
| `location`        | `{ latitude, longitude, address?, title? }` | Map location                                                                                                                                                                                   |
| `card`            | `{ title, subtitle?, imageUrl?, actions }`  | Rich card with action buttons                                                                                                                                                                  |
| `carousel`        | `{ items }`                                 | Horizontal scrollable list of cards                                                                                                                                                            |
| `choice`          | `{ text, options, disableFreeText? }`       | Quick reply buttons                                                                                                                                                                            |
| `dropdown`        | `{ text, options, disableFreeText? }`       | Dropdown select menu                                                                                                                                                                           |
| `bloc`            | `{ items }`                                 | A group of mixed message types sent together                                                                                                                                                   |
| `custom`          | `{ url, name, data? }`                      | Raw custom message referencing a bundled component by URL                                                                                                                                      |
| `customComponent` | `{ component, props }`                      | Send a [custom component](/adk/conversations/custom-components) directly. The runtime rewrites this into a `custom` message under the hood, so you get type-checked props instead of a raw URL |

Other channels (Slack, WhatsApp, Telegram) may support different message types. When you specify a channel on your conversation, TypeScript will only allow the message types that channel supports.

## Examples

### Card with actions

```typescript theme={null}
await conversation.send({
  type: "card",
  payload: {
    title: "Order #1234",
    subtitle: "Shipped - arriving Thursday",
    imageUrl: "https://example.com/product.jpg",
    actions: [
      { action: "url", label: "Track shipment", value: "https://example.com/track/1234" },
      { action: "postback", label: "Contact support", value: "contact_support" },
    ],
  },
})
```

### Carousel

```typescript theme={null}
await conversation.send({
  type: "carousel",
  payload: {
    items: [
      {
        title: "Basic Plan",
        subtitle: "$9/mo",
        imageUrl: "https://example.com/basic.png",
        actions: [{ action: "postback", label: "Select", value: "plan_basic" }],
      },
      {
        title: "Pro Plan",
        subtitle: "$29/mo",
        imageUrl: "https://example.com/pro.png",
        actions: [{ action: "postback", label: "Select", value: "plan_pro" }],
      },
    ],
  },
})
```

### Choice buttons

```typescript theme={null}
await conversation.send({
  type: "choice",
  payload: {
    text: "How would you like to proceed?",
    options: [
      { label: "Check order status", value: "check_order" },
      { label: "Start a return", value: "start_return" },
      { label: "Talk to a human", value: "talk_to_human" },
    ],
  },
})
```

### Markdown

```typescript theme={null}
await conversation.send({
  type: "markdown",
  payload: {
    markdown: "Here's a summary:\n\n- **Items**: 3\n- **Total**: $45.99\n- **Status**: Processing",
  },
})
```

## Typing indicators

The framework automatically starts a typing indicator when your handler begins and stops it when the handler finishes. You don't need to manage this yourself.

If you need manual control (e.g., you stopped typing to send a message and want to restart it before a slow operation), you can call the methods directly:

```typescript theme={null}
await conversation.startTyping()
await conversation.stopTyping()
```

## Conversation tags

Read and write metadata tags on the conversation:

```typescript theme={null}
const priority = conversation.tags.priority

conversation.tags.priority = "high"
conversation.tags.category = "billing"
```

<Note>
  Tags must be declared in `agent.config.ts` under `conversation.tags`. Check out our guide to [configuration your agent](/adk/setup/configuration#tags) for more information.
</Note>

## Loading a conversation by ID

You can send messages to any conversation, not just the current one:

```typescript theme={null}
import { Conversation } from "@botpress/runtime"

const otherConversation = await Conversation.get("conversation-id")
await otherConversation.send({
  type: "text",
  payload: { text: "Hello from another conversation!" },
})
```

This is useful for cross-conversation notifications or broadcasting messages.

## Combining with execute()

A common pattern is to send a direct message before or after handing control to the AI:

```typescript theme={null}
handler: async ({ execute, conversation, type }) => {
  if (type === "message") {
    await conversation.send({
      type: "text",
      payload: { text: "Let me look into that for you." },
    })

    await execute({
      instructions: "You are a helpful assistant.",
    })
  }
}
```

Direct sends and AI-generated messages appear in the same conversation.
