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

# Buttons

> Send one to five buttons, with or without text. A plain tap sends the label back as text; a URL button opens a page in the app.

A `buttons` part draws a vertical stack of one to five buttons, on its own or alongside text. Each item has a `label` of 1 to 80 characters and, for a URL button, a `url`. Only an agent can send buttons, and a Message carries at most one `buttons` part.

## Send buttons

This request contains a `text` part followed by a `buttons` part. The preview shows both in that order. Tap a button to try the reply; the demo stays in your browser and sends no request.

**Preview**

Which planet has the most moons?

**JSON**

```json theme={null}
{
  "message": {
    "parts": [
      {"type":"text","value":"Which planet has the most moons?"},
      {"type":"buttons","items":[
        {"label":"Jupiter"},
        {"label":"Saturn"},
        {"label":"Neptune"},
        {"label":"Mars"}
      ]}
    ]
  }
}
```

Send it through either [send path](https://docs.staging.relayapp.im/messages/send.md):

```typescript TypeScript SDK theme={null}
// question and choices are what your model wrote.
await relay.chats.messages.send(chatId, {
  message: {
    parts: [
      { type: "text", value: question },
      { type: "buttons", items: choices.map((label) => ({ label })) },
    ],
  },
});
```

```bash cURL theme={null}
curl -sS -X POST "https://api.staging.relayapp.im/v1/chats/$CHAT_ID/messages" \
  -H "Authorization: Bearer $RELAY_AGENT_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"message":{"parts":[{"type":"text","value":"<question your model wrote>"},{"type":"buttons","items":[{"label":"<choice 1>"},{"label":"<choice 2>"}]}]}}'
```

### Buttons without text

A Message can contain only a `buttons` part. Its `part_index` is `0`, so a plain tap replies to index `0` rather than index `1` in the example above.

**Preview**

One plain button, Continue, without a text part

**JSON**

```json theme={null}
{
  "message": {
    "parts": [
      {"type":"buttons","items":[
        {"label":"Continue"}
      ]}
    ]
  }
}
```

## Receive a tap

A plain-button tap is the person's next Message: one `text` part whose value is the label, with `reply_to` naming the buttons Message and its `part_index`. Your agent reads it like any other text. The button group leaves the screen after a plain tap, and the tap stays as the person's own bubble.

**Preview**

The tap, Jupiter, as the person's own bubble

**What you receive**

```json theme={null}
{
  "event_type": "message.received",
  "data": {
    "parts": [{"type":"text","value":"Jupiter"}],
    "reply_to": {"message_id":"01a0b5d5-2f9c-7502-9c18-b7c46c11f8af","part_index":1}
  }
}
```

The server accepts a reply to a `buttons` part only when it is one `text` part equal to one of that part's plain labels, sent by the user. A tap on a `url` button never reaches you.

## Send a URL button

A `url` button opens the page in a browser inside the app and sends nothing. Opening the URL leaves the button group visible, so the person can open it again.

Tap the button in the demo to see the in-app browser cover the chat, the way the app shows it. The demo loads nothing from the example site; close the browser to return to the chat.

**Preview**

Connect your Google account to continue.

**JSON**

```json theme={null}
{
  "message": {
    "parts": [
      {"type":"text","value":"Connect your Google account to continue."},
      {"type":"buttons","items":[
        {"label":"Connect Google","url":"https://accounts.example.com/oauth/authorize"}
      ]}
    ]
  }
}
```

### Mix choices and a URL button

A group can hold plain buttons and URL buttons together. A tap on a plain button hides the whole group, URL button included; a tap on the URL button opens the page and hides nothing.

**Preview**

Your Q3 report is ready.

**JSON**

```json theme={null}
{
  "message": {
    "parts": [
      {"type":"text","value":"Your Q3 report is ready."},
      {"type":"buttons","items":[
        {"label":"Approve"},
        {"label":"Open report","url":"https://reports.example.com/q3"}
      ]}
    ]
  }
}
```

## Send them from a runtime

Buttons are a property of the Message, so every runtime sends them through the send it already has: a backend includes the `buttons` part in `parts`, with or without a `text` part; a runtime with a send tool takes a `buttons` argument; and a runtime that answers in text ends the answer with a fenced code block tagged `buttons` holding the items array, which the bridge lifts into the part. Each [integration](https://docs.staging.relayapp.im/integrations/index.md) says which applies in its "What it can do" table.

## When it fails

| Status | Code | Cause |
| - | - | - |
| `400` | [1005](https://docs.staging.relayapp.im/api-reference/errors.md#1005) | No items or more than 5, a label missing or over 80 characters, two buttons parts in one Message, or an unknown field such as `id`. |
| `403` | [2003](https://docs.staging.relayapp.im/api-reference/errors.md#2003) | A user sent buttons, or an agent replied to a buttons part. |
| `422` | [2006](https://docs.staging.relayapp.im/api-reference/errors.md#2006) | A reply to a buttons part that is not one `text` part equal to one of its plain labels, or a reaction on a buttons part. |

## Next steps

* [Interactions](https://docs.staging.relayapp.im/interactions/index.md)
* [Send a message](https://docs.staging.relayapp.im/messages/send.md)
* [Replies](https://docs.staging.relayapp.im/messages/replies.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.