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

# Interactions

> The events you receive when someone clicks a button or submits a form.

Buttons and forms send events to your webhook through the same signed pipeline as messages. Each event carries its own `response_url`, so you can reply or update the original message.

The payloads are **flat** — `action_id`, `value`, and `user` sit at the top level. There is no wrapper object.

## interaction.button\_clicked

```json theme={null}
{
  "api_version": "2026-07-01",
  "block_kit_version": "1",
  "event": "interaction.button_clicked",
  "type": "interaction.button_clicked",
  "event_id": "evt_01JZYA7M3T",
  "chatbot_id": "c1d4",
  "conversation_id": "9f31",
  "message_id": "m_77ab",
  "block_id": "blk_x8f2",
  "action_id": "approve",
  "value": "req_991",
  "label": "Approve",
  "message_metadata": { "order_id": "4821" },
  "user": { "kind": "visitor", "id": "vs_8c2", "display_name": "Visitor 4821" },
  "clicked_at": "2026-07-17T03:12:44.120Z",
  "response_url": "https://app.my-aichatbot.com/api/v1/responses/eyJ2Ijox",
  "delivery_attempt": 1
}
```

<ResponseField name="action_id" type="string">
  The `action_id` from the button you made.
</ResponseField>

<ResponseField name="value" type="string">
  The button's `value`, exactly as you sent it. An empty string if you set none.
</ResponseField>

<ResponseField name="label" type="string | null">
  The button text at the time of the click.
</ResponseField>

<ResponseField name="message_metadata" type="object">
  A word-for-word copy of the `metadata` you set on the message. An empty object if you set none.
</ResponseField>

<ResponseField name="user" type="object">
  Who clicked.

  <Expandable title="properties">
    <ResponseField name="kind" type="string">
      `visitor` (widget or public page) or `member` (someone in your workspace).
    </ResponseField>

    <ResponseField name="id" type="string">
      The visitor session or member id.
    </ResponseField>

    <ResponseField name="display_name" type="string">
      A friendly name, like `Visitor 4821`.
    </ResponseField>
  </Expandable>
</ResponseField>

<Note>
  Link buttons (any button with a `url`) never send events. They just open a tab.
</Note>

## interaction.form\_submitted

Same base fields, with the answers in `values`:

```json theme={null}
{
  "api_version": "2026-07-01",
  "block_kit_version": "1",
  "event": "interaction.form_submitted",
  "type": "interaction.form_submitted",
  "event_id": "evt_01JZYB2N8Q",
  "chatbot_id": "c1d4",
  "conversation_id": "9f31",
  "message_id": "m_55cd",
  "block_id": "blk_p2m9",
  "action_id": "callback",
  "form_id": "callback",
  "values": {
    "full_name": "Priya Sharma",
    "email": "priya@example.com",
    "team_size": 14,
    "topic": "other",
    "details": "",
    "consent": true
  },
  "message_metadata": { "flow": "callback_request" },
  "user": { "kind": "visitor", "id": "vs_8c2", "display_name": "Visitor 4821" },
  "submitted_at": "2026-07-17T03:15:02.551Z",
  "response_url": "https://app.my-aichatbot.com/api/v1/responses/eyJ2Ijox",
  "delivery_attempt": 1
}
```

<ResponseField name="form_id" type="string">
  The form's `form_id` — the one you set, or the one we made if you left it out. It matches the event's `action_id`.
</ResponseField>

### How values are typed

| Field type                  | Value type                    | When left empty |
| --------------------------- | ----------------------------- | --------------- |
| `text`, `email`, `textarea` | string                        | `""`            |
| `number`                    | number                        | `null`          |
| `select`                    | string (the option's `value`) | `""`            |
| `checkbox`                  | boolean                       | `false`         |

**Every key is always there**, even when empty. Your field mappings will not break on a missing path.

<Note>
  We check answers on our servers before sending them to you. If a check fails, the visitor sees the errors inline and you get nothing. So anything that reaches you already passed your `required`, `min`, `max`, and `options` rules.
</Note>

## Replying

Every event carries its own `response_url`. The natural move is to swap the form for a confirmation:

```json theme={null}
{ "text": "Thanks Priya! We'll call **+61 400 000 000** tomorrow morning." }
```

Or return it straight from the webhook. Both work the same.

## Two fields that lie

<Warning>
  **`delivery_attempt` is always `1`.** It is written into the payload once and never changes on retry. For the real try number, read the `X-MyAIChatbot-Attempt` header.
</Warning>

Spot repeats with `event_id` — it *is* the same across retries. See [Receiving events](/receiving-events/webhooks).

## Button state

After we accept a click, the group turns off and the clicked button shows as chosen — unless you set `disable_on_click: false`. This state is saved on our side, so page reloads and other viewers all agree.

Buttons show as turned off when:

* The message is over 30 days old.
* A human has taken over the conversation.
* The conversation has passed its storage window.

<Note>
  Interactions do not turn on the typing dots by default.
</Note>
