# Custom commands

# Custom commands

Text commands and button commands are built from the same modal in the dashboard's **Commands** tab. A command saved with buttons attached is a button command; one without is a text command.

## Creating a bot command

The **Commands** tab lists every command for the bot and adds new ones with **Add Command**. The response is rich text.

Editing can flip a command either way: remove every button to make it a text command, or add one to make it a button command.

Custom commands answer in any chat the bot is in — they don't check the allowed-groups list.

## The response editor

Selecting text inside the response field pops up a formatting toolbar.

*Selection toolbar*

| Button | Does |
| --- | --- |
| Bold, Italic, Underline, Strikethrough | Standard text formatting |
| Monospace | Code formatting |
| Spoiler | Telegram spoiler |
| Hyperlink | Turns the selection into a link — the URL must start with `https://` |
| Remove link | Strips a link back to plain text |

The modal toolbar also has **Undo** / **Redo**, a premium emoji inserter and a divider inserter.

## The button board

Each button has a label, a URL, a colour, a layout and an optional premium-emoji icon.

#### Button board limits

| Setting | Value |
| --- | --- |
| Buttons per command | 12 |
| Label length | 64 characters |
| URL scheme | `https://` only. A bare host gets `https://` added; an `http://` URL is rejected on save: `Button URLs must use HTTPS` |
| Colours | Gray (default), Blue, Green, Red |
| Layout | **Horizontal** or **Stacked** — Stacked is the default |

A button can carry one premium emoji next to its label, picked from your own emoji packs or pasted as a premium emoji ID (5 to 32 digits).

## Handling duplicate command triggers

A trigger must be unique across every text command, button command and character trigger on the same bot.

*Trigger validation errors*

| Situation | Message |
| --- | --- |
| Bad format | `Trigger must be alphanumeric (letters, numbers, underscore only)` |
| Matches a character's trigger | `Trigger cannot be the same as a character command (/x)` |
| Matches another text command | `Command with trigger "x" already exists` |
| Matches another button command | `Button command with trigger "x" already exists` |
| A text and a button command would share one trigger | `A button command with trigger "x" already exists. Triggers must be unique across text and button commands.` |

#### Slash optional

| Input | Output |
| --- | --- |
| Saved trigger | `ca` |
| All of these match | `/ca     /ca@yourbotusername     ca` |

Built-in commands are matched first, so a custom command whose trigger matches one of them doesn't get to answer.

#### Reserved trigger words

A character's trigger command can't be renamed to one of these 7 built-in words:

- start
- commands
- getid
- holders
- ban
- mute

## Limits

#### Per-command limits

| Setting | Value |
| --- | --- |
| Visible reply length | 4096 characters — Telegram's cap |

Over the limit, saving fails with `Response exceeds Telegram's 4096 character limit (N visible characters)`.

## Hyperlink navigation entries

> **Beta**
>
> Hyperlink navigation is currently in beta.

The Commands tab can edit a hyperlink navigation entry but not create one — new ones start from the Beta tab's nav builder. A nav entry can't be cloned or converted to a button command.

- [Hyperlink navigation](/creator-tools/nav-what-it-is)
