> ## Documentation Index
> Fetch the complete documentation index at: https://docs.osvi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Interactive Messages

> Buttons, carousels, and date pickers an agent can send, and how to answer them

Besides plain text, a chat agent can send a structured **interactive message** — buttons, a carousel, or a date picker — and wait for the customer to answer it before continuing. Interactive messages arrive the same way regular messages do (a reply on [Send Message](/api-reference/endpoint/chat/send_message), a callback on the [delivery webhook](/api-reference/endpoint/chat/delivery_webhook), or an event over the [chat WebSocket](/api-reference/chat-websocket)), tagged `type: "interaction"`.

<Note>
  Whether an agent offers interactive messages at all depends on its configuration. If your integration can't render a given type, declare what you *can* render with `supported_interactions` on every inbound request — the agent only offers types your client has declared.
</Note>

## Declaring what you support

Send `supported_interactions` on `content`/message requests to tell the agent which interaction types your client can display:

```json theme={null}
"supported_interactions": [
  { "tool_type": "ui_buttons", "schema_version": 2 },
  { "tool_type": "ui_date_picker", "schema_version": 1 }
]
```

| `tool_type` | Description |
| - | - |
| `ui_buttons` | A label plus a row of tappable options. Schema version `2` additionally supports one free-text option. |
| `ui_carousel` | A label plus a horizontally-scrollable list of items, each with a title and optional image. |
| `ui_date_picker` | A single date or a date range, constrained to an allowed window. |

Omit `supported_interactions` (or send an empty array) on a plain text message — the agent then won't offer any interactive type for that turn.

## What the agent sends

An interactive message is a message with `type: "interaction"`:

| Field | Description |
| - | - |
| `interaction_id` | UUID identifying this interactive message. Use it to answer it. |
| `tool_type` | `ui_buttons`, `ui_carousel`, or `ui_date_picker`. |
| `schema_version` | Version of the type's schema (see tables below). |
| `presentation` | The content to render — shape depends on `tool_type` (see below). |
| `interaction_status` | `pending` while waiting for an answer, `accepted` once answered, `cancelled` if superseded (e.g. the customer sent a plain message instead), `expired` if it timed out unanswered. |

### `ui_buttons` presentation

```json theme={null}
{
  "label": "Would you like to confirm this appointment?",
  "description": "You can also let me know if you'd like to reschedule.",
  "options": [
    { "id": "opt_confirm", "label": "Confirm" },
    { "id": "opt_other", "label": "Something else", "allow_input": true, "input_placeholder": "Tell me more..." }
  ]
}
```

`description` and each option's `description` are optional. At most one option may have `allow_input: true` (schema version 2 only) — selecting it lets the customer type free text instead of a fixed answer.

### `ui_carousel` presentation

```json theme={null}
{
  "label": "Here are a few options for you",
  "items": [
    {
      "id": "item_1",
      "title": "Deluxe Room",
      "description": "King bed, city view",
      "image": { "url": "https://cdn.example.com/deluxe.jpg", "alt": "Deluxe room" },
      "action_label": "Select"
    }
  ]
}
```

`description`, `image`, and `action_label` are optional per item.

### `ui_date_picker` presentation

```json theme={null}
{
  "label": "Pick a date for your appointment",
  "selection_mode": "single",
  "min_date": "2026-06-10",
  "max_date": "2026-07-10"
}
```

`selection_mode` is `single` (answer with one date) or `range` (answer with a start and end date). `min_date`/`max_date` bound the selectable range and may be omitted.

## Answering an interactive message

Send an inbound request (Send Message, Send Message Async, or a WebSocket message frame) with:

| Field | Description |
| - | - |
| `type` | `"interaction_response"`. |
| `interaction_id` | The `interaction_id` from the message you're answering. |
| `option_id` | Shorthand for a plain `ui_buttons` (schema version 1 only) tap — the `id` of the selected option. Use this **or** `response`, not both. For carousel, date picker, or `ui_buttons` schema version 2, use `response` instead. |
| `response` | `{ "kind": ..., "value": ... }` — see below. Required for every interaction type except a `ui_buttons` v1 tap, where `option_id` is a shorthand for the same thing. |

`response.kind` depends on what you're answering:

| `kind` | `value` | When to use it |
| - | - | - |
| `selection` | The selected option/item `id` (string) | `ui_carousel` selections, and `ui_buttons` schema version 2 (the `option_id` shorthand only works for version 1). |
| `text` | Typed text (string) | Only when the presentation has an option with `allow_input: true` (`ui_buttons` v2). |
| `date` | An ISO date, e.g. `"2026-06-12"` | `ui_date_picker` with `selection_mode: "single"`. |
| `date_range` | `{ "start_date": "...", "end_date": "..." }` | `ui_date_picker` with `selection_mode: "range"`. |

```json theme={null}
{
  "agent_uuid": "agent_IsZ3Q6Sf_60Eh26XQMGbz-R_og",
  "customer_id": "+15551112222",
  "type": "interaction_response",
  "interaction_id": "b6a3e6c2-2d61-4a4b-9c9a-5a2d9f6a2b10",
  "response": { "kind": "date_range", "value": { "start_date": "2026-06-10", "end_date": "2026-06-14" } }
}
```

A `response` is validated against the exact message you're answering — a `selection` id that isn't among its options/items, or a date outside `min_date`/`max_date`, is rejected with a `422`. Answering the same interaction twice with the same content (a retry, or a duplicate tap) returns the original answer instead of accepting a second one.
