Регистрация команд
Команды — единственный inbound-канал «юзер → бот». Обычные сообщения юзеров боту как webhook не доставляются (контент чата E2E-encrypted); бот узнаёт о вызове только через slash-команду, которую юзер явно выбрал. Поэтому набор команд бот должен сначала задекларировать.
Регистрация глобальна для бота (не привязана к space). Видимость и доставка
команд в конкретном space гейтятся scope commands в membership бота — он
запрашивается при invite, а не в декларации команды.
Bulk-overwrite
PUT /api/bot/commands декларирует весь набор команд бота за один запрос.
Это полная замена реестра (idempotent overwrite): что не вошло в тело —
удаляется. Чтобы изменить одну команду, отправьте весь актуальный список целиком.
commandsCommandDTO[]requiredПолный набор команд бота. Максимум MAX_COMMANDS_PER_BOT = 100 команд
(больше → 422). Дубли по name (после нормализации) → 400.
CommandDTO
namestringrequiredИмя команды без /. Нормализуется: strip() + lower(). Должно совпасть с
regex ^[a-z0-9_-]{1,32}$ (строчные латинские буквы, цифры, _, -;
длина 1..32). Нарушение charset → 400; длина вне 1..32 → 422 (Pydantic).
descriptionstringrequiredОписание команды. После strip() — длина 1..100 символов. Длина вне
диапазона → 422 (Pydantic); пустое после strip() → 400.
optionsCommandOptionDTO[]default: []Опции (аргументы) команды. Максимум MAX_OPTIONS_PER_COMMAND = 25 на
команду (больше → 422). Подробнее о полях опции — Опции команд.
Required-опции обязаны идти ДО optional. Как только в списке встретилась
опция с required: false, все последующие тоже должны быть optional. Нарушение
порядка → 400 (required options must come before optional ones).
Пример
result = await bot.client.register_commands([
{
"name": "weather",
"description": "Прогноз погоды для города",
"options": [
{
"name": "city",
"type": "string",
"description": "Название города",
"required": True, # required — первым
},
{
"name": "days",
"type": "integer",
"description": "На сколько дней вперёд",
"required": False, # optional — после required
"min": 1,
"max": 7,
},
],
},
{
"name": "ping",
"description": "Проверка отклика бота",
},
])
# result — список зарегистрированных команд с version и enabled
curl -X PUT https://api.reasonspace.ru/api/bot/commands \
-H "Authorization: Bot bot_..." \
-H "Content-Type: application/json" \
-d '{
"commands": [
{
"name": "weather",
"description": "Прогноз погоды для города",
"options": [
{"name": "city", "type": "string", "description": "Название города", "required": true},
{"name": "days", "type": "integer", "description": "На сколько дней вперёд", "required": false, "min": 1, "max": 7}
]
},
{"name": "ping", "description": "Проверка отклика бота"}
]
}'
Ответ
Возвращает массив зарегистрированных команд (200 OK):
namestringКаноничное (нормализованное) имя.
descriptionstringНормализованное описание.
optionsobject[]Нормализованные опции (с приведёнными типами и полями).
versionintegerВерсия записи команды на бэке.
enabledbooleanВключена ли команда (видна юзерам и вызываема).
PUT идемпотентен: повторная отправка того же набора даёт тот же реестр.
Регистрация пишется в audit-log (command.register).
Список команд
GET /api/bot/commands возвращает текущий реестр бота (тот же формат
CommandResponse[], что и ответ PUT).
commands = await bot.client.list_commands()
curl https://api.reasonspace.ru/api/bot/commands \
-H "Authorization: Bot bot_..."
Удалить команду
DELETE /api/bot/commands/{name} удаляет одну команду по имени. Имя
нормализуется (strip().lower()) до удаления. Возвращает 204 No Content.
await bot.client.delete_command("ping")
curl -X DELETE https://api.reasonspace.ru/api/bot/commands/ping \
-H "Authorization: Bot bot_..."
Для полной перезаписи реестра используйте PUT — он сам удалит то, что не вошло
в набор. DELETE нужен для точечного удаления одной команды.
Errors
| HTTP | Что значит |
|---|---|
| 400 | Доменная валидация: charset имени (regex ^[a-z0-9_-]{1,32}$), дубль имени, нарушен порядок required/optional, неверный тип опции, choices/min/max не для своего типа, пустое описание после strip() |
| 422 | Pydantic-лимиты: команд > 100, опций > 25, длина имени вне 1..32, длина описания вне 1..100 |
| 401 | Bad/expired token (Authorization: Bot) |
| 429 | Общий api-лимит бота (check_api). Заголовок Retry-After этот эндпоинт не возвращает |
429 — это общий rate-limit bot-API (check_api), а не отдельный лимит
команд. Этот эндпоинт не возвращает заголовок Retry-After; SDK при 429
повторяет запрос автоматически с фиксированной паузой.
Дальше
- Опции команд — типы, choices, min/max.
- Вызов команды — как юзер вызывает команду.
- Событие и ответ —
command.invokedи эфемерный ответ инвокеру.