Перейти к основному содержимому

Регистрация команд

Команды — единственный 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()
422Pydantic-лимиты: команд > 100, опций > 25, длина имени вне 1..32, длина описания вне 1..100
401Bad/expired token (Authorization: Bot)
429Общий api-лимит бота (check_api). Заголовок Retry-After этот эндпоинт не возвращает

429 — это общий rate-limit bot-API (check_api), а не отдельный лимит команд. Этот эндпоинт не возвращает заголовок Retry-After; SDK при 429 повторяет запрос автоматически с фиксированной паузой.

Дальше