Методы

Все методы — под адресом https://api.bot.marx.moscow/api/bot/v1/, с заголовком Authorization: Bearer marx_pat_….

В примерах $MARX_TOKEN — токен бота, $CHAT_ID — номер чата из GET /chats или из обновления, $MESSAGE_ID — номер сообщения. Задайте их в оболочке перед запуском:

export MARX_TOKEN=marx_pat_...
export CHAT_ID=812
export MESSAGE_ID=90211
МетодПутьЧто делает
GET/meАккаунт бота
GET/chatsЧаты, в которых состоит бот
POST/messagesОтправить сообщение
POST/mediaЗагрузить картинку, видео или файл
POST/reactionsПоставить или снять реакцию
POST/channelsСоздать свой канал
GET/updatesПолучить обновления (длинный опрос)
POST, DELETE/webhookЗадать или снять вебхук
PUT, GET, DELETE/commandsКоманды бота в меню приложения

GET /me

Аккаунт, которому принадлежит токен. Удобно для проверки токена при запуске.

Поле ответаТипЧто это
user_idцелоеНомер аккаунта бота
usernameстрокаИмя пользователя без @
display_nameстрокаИмя, которое видят в чатах
token_nameстрокаИмя токена; у токена от @marxbot — bot
is_botлогическоеtrue у бота
curl https://api.bot.marx.moscow/api/bot/v1/me \
  -H "Authorization: Bearer $MARX_TOKEN"
{"user_id": 41207, "username": "dacha_weather_bot", "display_name": "Погода на даче", "token_name": "bot", "is_bot": true}

GET /chats

Все чаты, в которых состоит бот, в порядке списка чатов приложения.

Поле элементаТипЧто это
idцелоеНомер чата, chat_id в других методах
typeстрокаdirect — личный, group — группа, channel — канал
titleстрока или nullНазвание; у личного чата null
curl https://api.bot.marx.moscow/api/bot/v1/chats \
  -H "Authorization: Bearer $MARX_TOKEN"
[{"id": 812, "type": "group", "title": "Дача"}, {"id": 977, "type": "direct", "title": null}]

POST /messages

Отправить сообщение в чат, где бот — участник с правом писать. В группе это право у участников есть по умолчанию, в канале — только у администратора. Начать личный чат бот не может: он появляется, когда человек пишет боту.

Поле запросаТипЧто это
chat_idцелое, обязательноНомер чата
kindстрокаtext (по умолчанию), image, video, file или poll
bodyстрокаТекст, до 8192 символов; для text не может быть пустым
media_idцелоеДля image, video, file: номер из POST /media этого же бота
captionстрокаПодпись к картинке, видео или файлу, до 8192 символов
file_name, file_sizeстрока, целоеИмя и размер файла для file
questionстрокаДля poll: вопрос, до 300 символов
optionsмассив строкДля poll: от 2 до 10 вариантов, каждый до 100 символов; пустые отбрасываются
anonymous, multiple, revoteлогическоеДля poll: анонимный (по умолчанию да), несколько ответов (нет), можно переголосовать (да)
client_idстрокаДо 64 символов. Повтор с тем же client_id в течение часа не создаёт второе сообщение и не расходует предел
composed_at_msцелоеВозвращается в ответе как есть
Поле ответаЧто это
message_idНомер сообщения
duplicatetrue, если это повтор по client_id; тогда в ответе только message_id и duplicate
messageСообщение, тот же объект, что в обновлении
composed_at_msЗначение из запроса или null

Текст

curl https://api.bot.marx.moscow/api/bot/v1/messages \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{"chat_id": $CHAT_ID, "body": "Завтра +18, без осадков", "client_id": "forecast-2026-10-05"}
EOF
{
  "message_id": 90230,
  "duplicate": false,
  "message": {
    "id": 90230,
    "chat_id": 812,
    "sender_id": 41207,
    "author": {"id": 41207, "display_name": "Погода на даче", "username": "dacha_weather_bot", "avatar_key": null, "avatar_url": null, "is_bot": true},
    "seq": 5121,
    "type": "text",
    "body": "Завтра +18, без осадков",
    "caption": null,
    "created_at": "2026-10-05T07:00:00.412Z",
    "media_url": null,
    "object_key": null,
    "media": null,
    "attachments": [],
    "edited_at": null,
    "call_status": null,
    "call_duration": null,
    "reply_to_message_id": null,
    "quote": null,
    "views": 0,
    "comment_count": 0,
    "poll": null,
    "forwarded_from_user_id": null,
    "forwarded_from_chat_id": null,
    "forwarded_from_name": null,
    "about_user_id": null,
    "about_name": null,
    "reactions": [],
    "duration_ms": null,
    "file_name": null,
    "file_size": null
  },
  "composed_at_ms": null
}

Повтор с тем же client_id

curl https://api.bot.marx.moscow/api/bot/v1/messages \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{"chat_id": $CHAT_ID, "body": "Завтра +18, без осадков", "client_id": "forecast-2026-10-05"}
EOF
{"message_id": 90230, "duplicate": true}

Опрос

curl https://api.bot.marx.moscow/api/bot/v1/messages \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{"chat_id": $CHAT_ID, "kind": "poll", "question": "Когда едем?", "options": ["Суббота", "Воскресенье"]}
EOF
{
  "message_id": 90231,
  "duplicate": false,
  "message": {
    "id": 90231,
    "chat_id": 812,
    "sender_id": 41207,
    "author": {"id": 41207, "display_name": "Погода на даче", "username": "dacha_weather_bot", "avatar_key": null, "avatar_url": null, "is_bot": true},
    "seq": 5122,
    "type": "poll",
    "body": "{\"question\": \"Когда едем?\", \"options\": [\"Суббота\", \"Воскресенье\"], \"closed\": false}",
    "caption": null,
    "created_at": "2026-10-05T07:00:02.035Z",
    "media_url": null,
    "object_key": null,
    "media": null,
    "attachments": [],
    "edited_at": null,
    "call_status": null,
    "call_duration": null,
    "reply_to_message_id": null,
    "quote": null,
    "views": 0,
    "comment_count": 0,
    "poll": {
      "question": "Когда едем?",
      "closed": false,
      "my_vote": null,
      "my_votes": [],
      "total": 0,
      "voters": 0,
      "anonymous": true,
      "multiple": false,
      "revote": true,
      "can_close": true,
      "recent_voters": [],
      "options": [{"label": "Суббота", "count": 0}, {"label": "Воскресенье", "count": 0}]
    },
    "forwarded_from_user_id": null,
    "forwarded_from_chat_id": null,
    "forwarded_from_name": null,
    "about_user_id": null,
    "about_name": null,
    "reactions": [],
    "duration_ms": null,
    "file_name": null,
    "file_size": null
  },
  "composed_at_ms": null
}

Ошибки

Кодdetail
400an empty post says nothing, a poll needs a question and two options, a image post needs a media_id
403this account cannot post here — у бота нет права писать в этот чат
404chat not found — чата нет или бот в нём не состоит
422not your attachment, unknown attachment — media_id загрузил не этот бот или его нет

POST /media

Загрузить картинку, видео или файл, чтобы затем отправить его через POST /messages с media_id. Тело — multipart/form-data.

Поле формыЧто это
fileФайл, обязательно. Картинка до 50 МБ, видео до 320 МБ, файл до 50 МБ. Для image и video тип файла (Content-Type части) должен быть image/… или video/…
kindimage (по умолчанию), video или file
duration_msДля видео: длительность в миллисекундах
posterДля видео: кадр-обложка, картинка

Ответ: media_id, size в байтах, width и height для картинки (иначе null). Отказ — 400 с причиной в detail, например not a readable image.

curl https://api.bot.marx.moscow/api/bot/v1/media \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -F kind=image -F "file=@map.png;type=image/png"
{"media_id": 5521, "size": 183204, "width": 1280, "height": 720}

Затем:

{"chat_id": 812, "kind": "image", "media_id": 5521, "caption": "Карта осадков"}

POST /reactions

Поставить реакцию на сообщение в чате, где состоит бот. Тот же запрос второй раз снимает её.

Поле запросаТипЧто это
message_idцелое, обязательноНомер сообщения
emojiстрока, обязательноЭмодзи, от 1 до 16 символов
curl https://api.bot.marx.moscow/api/bot/v1/reactions \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{"message_id": $MESSAGE_ID, "emoji": "👍"}
EOF
{"ok": true}

Сообщения нет или бот не состоит в его чате — 404 message not found.

POST /channels

Канал, владелец которого — бот, с этим названием. Если у бота уже есть канал с таким названием, возвращается он, иначе создаётся новый. Людей в канал добавляют из приложения.

ПолеЧто это
titleЗапрос: название, от 1 до 128 символов
idОтвет: номер канала
createdОтвет: true, если канал создан этим запросом
curl https://api.bot.marx.moscow/api/bot/v1/channels \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title": "Погода на даче"}'
{"id": 1304, "title": "Погода на даче", "created": true}

GET /updates

Новые сообщения для бота. Как это устроено — в разделе Длинный опрос.

ПараметрПо умолчаниюЧто это
offset0Номер первого нужного обновления. Все обновления с меньшим update_id считаются полученными и удаляются
limit100Сколько обновлений вернуть, от 1 до 100
timeout0Сколько секунд ждать, если обновлений нет, от 0 до 50
curl "https://api.bot.marx.moscow/api/bot/v1/updates?offset=0&timeout=30" \
  -H "Authorization: Bearer $MARX_TOKEN"
[
  {
    "update_id": 7,
    "chat": {"id": 812, "type": "group", "title": "Дача"},
    "message": {
      "id": 90229,
      "chat_id": 812,
      "sender_id": 40011,
      "author": {"id": 40011, "display_name": "Анна", "username": "anna", "avatar_key": null, "avatar_url": null, "is_bot": false},
      "seq": 5120,
      "type": "text",
      "body": "/today@dacha_weather_bot",
      "caption": null,
      "created_at": "2026-10-05T06:59:58.101Z",
      "media_url": null,
      "object_key": null,
      "media": null,
      "attachments": [],
      "edited_at": null,
      "call_status": null,
      "call_duration": null,
      "reply_to_message_id": null,
      "quote": null,
      "views": 0,
      "comment_count": 0,
      "poll": null,
      "forwarded_from_user_id": null,
      "forwarded_from_chat_id": null,
      "forwarded_from_name": null,
      "about_user_id": null,
      "about_name": null,
      "reactions": [],
      "duration_ms": null,
      "file_name": null,
      "file_size": null
    }
  }
]

Задан вебхук — 409 webhook is set.

POST /webhook, DELETE /webhook

POST задаёт адрес, на который Marx отправляет каждое обновление; GET /updates после этого отвечает 409. DELETE снимает вебхук; неотправленные обновления остаются и приходят через GET /updates. Подробнее — Вебхук.

Поле запросаЧто это
urlОбязательно. Только https://, до 512 символов; адрес должен быть публичным
secretДо 256 символов из A-Z, a-z, 0-9, _, -. Приходит в заголовке X-Marx-Bot-Secret каждого запроса
curl https://api.bot.marx.moscow/api/bot/v1/webhook \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://bot.example.org/marx", "secret": "Zr4q-8NnYtV2"}'
{"ok": true, "url": "https://bot.example.org/marx"}
curl -X DELETE https://api.bot.marx.moscow/api/bot/v1/webhook \
  -H "Authorization: Bearer $MARX_TOKEN"
{"ok": true}

Адрес не принят — 400 с причиной: only https is allowed, the address is not public, the host does not resolve и другие.

PUT /commands, GET /commands, DELETE /commands

Список команд, который приложение показывает в меню чата с ботом. PUT заменяет весь список, DELETE очищает его. Правила — в разделе Команды.

curl -X PUT https://api.bot.marx.moscow/api/bot/v1/commands \
  -H "Authorization: Bearer $MARX_TOKEN" \
  -H "Content-Type: application/json" \
  -d @- <<EOF
{"commands": [
  {"command": "today", "description": "Погода на сегодня"},
  {"command": "week", "description": "Прогноз на неделю"}
]}
EOF
{"commands": [{"command": "today", "description": "Погода на сегодня"}, {"command": "week", "description": "Прогноз на неделю"}]}
curl https://api.bot.marx.moscow/api/bot/v1/commands \
  -H "Authorization: Bearer $MARX_TOKEN"
{"commands": [{"command": "today", "description": "Погода на сегодня"}, {"command": "week", "description": "Прогноз на неделю"}]}
curl -X DELETE https://api.bot.marx.moscow/api/bot/v1/commands \
  -H "Authorization: Bearer $MARX_TOKEN"

Список не прошёл проверку — 400, в detail — какой элемент и что с ним, например commands[1].command: must match ^[a-z0-9_]{1,32}$, without the /. Токен человека, а не бота, — 403 this account is not a bot.