Bot API

HTTP-интерфейс для ботов мессенджера Chatto. Он устроен так же, как Telegram Bot API: большинство библиотек и привычных приёмов переносятся с минимальными правками.

Базовый адрес https://core.chatto.is/api/v1/bot/<ТОКЕН>/<метод>
1

Создайте бота

Откройте в Chatto @botstudio и нажмите «Создать бота». Адрес бота должен заканчиваться на bot.

2

Получите токен

Токен вида 123:AbC… находится в настройках бота. Храните его как пароль.

3

Подключите сервер

Получайте обновления через getUpdates или вебхук и отвечайте методом sendMessage.

Быстрый старт

Эхо-бот за минуту: получаем сообщения и отвечаем тем же текстом.

# 1. Проверяем токен
TOKEN=123:AbCdEf...
curl "https://core.chatto.is/api/v1/bot/$TOKEN/getMe"

# 2. Ждём сообщения (long polling до 25 секунд)
curl "https://core.chatto.is/api/v1/bot/$TOKEN/getUpdates?timeout=25"

# 3. Отвечаем в чат из message.chat.id
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/sendMessage" \
  -H 'Content-Type: application/json' \
  -d '{"chat_id": 7, "text": "Привет!"}'
Бот пишет только в чаты, где он участник. Личный чат начинает пользователь — сообщением боту или кнопкой «Запустить» (придёт /start). В группах бот получает команды и сообщения с упоминанием @имя_бота.

Запросы и ответы

Все методы принимают GET и POST: параметры в строке запроса, application/json или form-data.

Успех

{"ok": true, "result": …}

Ошибка

{"ok": false, "error_code": 400,
 "description": "Bad Request: …"}

Получение обновлений

Два способа — выберите один. Пока установлен вебхук, getUpdates возвращает ошибку 409.

Long polling

Вызывайте getUpdates в цикле с timeout=25 и offset, равным последнему update_id + 1. Удобно при разработке — не нужен публичный адрес.

Вебхук

После setWebhook Chatto отправляет каждое обновление POST-запросом на ваш HTTPS-адрес с заголовком X-Chatto-Bot-Api-Secret-Token. Ответьте кодом 2xx, иначе доставка повторится.

Кнопки под сообщениями

reply_markup.inline_keyboard — до 10 рядов по 8 кнопок. Кнопка открывает ссылку, мини-приложение или присылает боту callback_query.

{
  "inline_keyboard": [
    [{"text": "Нравится", "callback_data": "like:42"}],
    [{"text": "Открыть каталог", "web_app": {"url": "https://shop.example"}}],
    [{"text": "Сайт", "url": "https://chatto.is"}]
  ]
}
После нажатия кнопки с callback_data у пользователя показывается индикатор загрузки, пока бот не ответит answerCallbackQuery. На ответ — 5 секунд.

Mini Apps

Веб-приложения, которые открываются прямо в Chatto: магазины, сервисы, формы, игры. API совместим с Telegram Web Apps — код, написанный под Telegram.WebApp, работает без правок.

Как открыть мини-приложение

СпособКак настроить
Кнопка менюsetChatMenuButton с type: "web_app" — кнопка слева от поля ввода в чате с ботом
Кнопка под сообщением{"text": "Каталог", "web_app": {"url": "https://…"}} в inline_keyboard
Профиль ботаsetMainWebApp — кнопка «Открыть приложение» в профиле
Ссылкаhttps://chatto.is/app/имя_бота?startapp=promo — параметр придёт в initDataUnsafe.start_param

Подключение SDK

Внутри Chatto SDK подключается автоматически. Добавьте его явно, чтобы страница работала и в обычном браузере:

<script src="https://chatto.is/js/chatto-web-app.js"></script>
<script>
  const app = window.Chatto.WebApp;   // то же, что window.Telegram.WebApp
  app.ready();
  app.MainButton.setText('Купить за 990 ₽').show().onClick(() => {
    app.HapticFeedback.impactOccurred('medium');
    fetch('/api/order', { method: 'POST', body: app.initData });   // проверьте подпись на сервере
  });
</script>

Возможности SDK

APIОписание
initDataПодписанные данные запуска: user, query_id, start_param, auth_date, hash
themeParamsЦвета приложения и CSS-переменные --tg-theme-bg-color, --tg-theme-text-color, --tg-theme-button-color и другие
MainButtonНативные кнопки внизу экрана (также SecondaryButton): текст, цвет, индикатор загрузки, блик
BackButtonКнопка «Назад» в шапке; SettingsButton — пункт «Настройки» в меню
HapticFeedbackimpactOccurred, notificationOccurred, selectionChanged
showPopupНативные окна до трёх кнопок; также showAlert и showConfirm
showScanQrPopupВстроенный сканер QR-кодов
CloudStorageХранилище «ключ — значение» для пары бот и пользователь: до 1024 ключей, значения до 4096 символов
sendDataСтрока до 4096 байт боту — придёт как message.web_app_data, приложение закроется
openLinkОткрыть ссылку в браузере; openChattoLink — ссылку Chatto внутри приложения
прочееreadTextFromClipboard, expand, close, enableClosingConfirmation, setHeaderColor, setBackgroundColor — как в Telegram

Проверка initData на сервере

Не доверяйте initDataUnsafe — проверяйте подпись. Алгоритм такой же, как в Telegram: secret = HMAC_SHA256(key="WebAppData", data=токен), затем hash = hex(HMAC_SHA256(key=secret, data=data_check_string)), где data_check_string — все поля, кроме hash, в виде ключ=значение, отсортированные по алфавиту и соединённые символом \n.

# Python
import hmac, hashlib
from urllib.parse import parse_qsl

def check(init_data: str, token: str) -> bool:
    data = dict(parse_qsl(init_data))
    received = data.pop("hash", "")
    check_string = "\n".join(f"{k}={v}" for k, v in sorted(data.items()))
    secret = hmac.new(b"WebAppData", token.encode(), hashlib.sha256).digest()
    return hmac.compare_digest(hmac.new(secret, check_string.encode(), hashlib.sha256).hexdigest(), received)
Не хотите считать HMAC самостоятельно — вызовите validateWebAppData. Живой пример — демо мини-приложение; в Chatto оно открывается кнопкой «Демо Mini App» в @botstudio.

Бот

getMe

GET · POST #
Возвращает User

Информация о боте. Удобно, чтобы проверить токен.

Без параметров.

curl "https://core.chatto.is/api/v1/bot/$TOKEN/getMe"
Ответ — поле result
{
  "id": 42,
  "is_bot": true,
  "first_name": "Погода",
  "username": "weather_bot",
  "can_join_groups": true
}

Обновления

getUpdates

GET · POST #
Возвращает Array of Update

Long polling: возвращает накопившиеся обновления. Обновления с id меньше offset считаются подтверждёнными и удаляются. Не работает, пока установлен вебхук.

ПараметрТипОписание
offset
необязательный
Integer id первого нужного обновления (последний полученный update_id + 1)
limit
необязательный
Integer 1–100, по умолчанию 100
timeout
необязательный
Integer Сколько секунд ждать новых обновлений (0–25)
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/getUpdates" \
  -H 'Content-Type: application/json' \
  -d '{
    "offset": 18,
    "timeout": 25
  }'
Ответ — поле result
[
  {
    "update_id": 18,
    "message": {
      "message_id": 501,
      "text": "/start",
      "chat": {
        "id": 7,
        "type": "private"
      },
      "from": {
        "id": 8,
        "is_bot": false,
        "first_name": "Dias"
      },
      "date": 1759300000
    }
  }
]

setWebhook

GET · POST #
Возвращает True

Присылать обновления POST-запросом на ваш HTTPS-адрес. Ошибки доставки повторяются до 5 раз с паузой.

ПараметрТипОписание
url
обязательный
String HTTPS-адрес; пустая строка — снять вебхук
secret_token
необязательный
String Придёт в заголовке X-Chatto-Bot-Api-Secret-Token — проверяйте его
drop_pending_updates
необязательный
Boolean Удалить накопившиеся обновления
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/setWebhook" \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://example.com/bot",
    "secret_token": "s3cret"
  }'
Ответ — поле result
true

deleteWebhook

GET · POST #
Возвращает True

Снять вебхук и вернуться к getUpdates.

ПараметрТипОписание
drop_pending_updates
необязательный
Boolean Удалить накопившиеся обновления
curl "https://core.chatto.is/api/v1/bot/$TOKEN/deleteWebhook"
Ответ — поле result
true

getWebhookInfo

GET · POST #
Возвращает WebhookInfo

Текущий вебхук, сколько обновлений ждёт доставки и последняя ошибка.

Без параметров.

curl "https://core.chatto.is/api/v1/bot/$TOKEN/getWebhookInfo"
Ответ — поле result
{
  "url": "https://example.com/bot",
  "has_custom_certificate": false,
  "pending_update_count": 0
}

Сообщения

sendMessage

GET · POST #
Возвращает Message

Отправить сообщение в чат, где бот участник. Личный чат начинает пользователь.

ПараметрТипОписание
chat_id
обязательный
Integer id чата из message.chat.id
text
обязательный
String Текст, до 4096 символов. Поддерживается **жирный**, _курсив_, `код`
reply_to_message_id
необязательный
Integer Ответить на сообщение
reply_markup
необязательный
InlineKeyboardMarkup Кнопки под сообщением
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/sendMessage" \
  -H 'Content-Type: application/json' \
  -d '{
    "chat_id": 7,
    "text": "Привет! Выберите город",
    "reply_markup": {
      "inline_keyboard": [
        [
          {
            "text": "Москва",
            "callback_data": "city:msk"
          },
          {
            "text": "Сайт",
            "url": "https://chatto.is"
          }
        ]
      ]
    }
  }'
Ответ — поле result
{
  "message_id": 777,
  "chat": {
    "id": 7,
    "type": "private"
  },
  "text": "Привет! Выберите город",
  "date": 1759300001
}

editMessageText

GET · POST #
Возвращает Message

Изменить текст своего сообщения. Без reply_markup кнопки убираются (как в Telegram).

ПараметрТипОписание
chat_id
обязательный
Integer id чата
message_id
обязательный
Integer id сообщения бота
text
обязательный
String Новый текст
reply_markup
необязательный
InlineKeyboardMarkup Новые кнопки
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/editMessageText" \
  -H 'Content-Type: application/json' \
  -d '{
    "chat_id": 7,
    "message_id": 777,
    "text": "Москва выбрана"
  }'
Ответ — поле result
{
  "message_id": 777,
  "text": "Москва выбрана",
  "edit_date": 1759300009
}

editMessageReplyMarkup

GET · POST #
Возвращает Message

Заменить или убрать кнопки под сообщением бота.

ПараметрТипОписание
chat_id
обязательный
Integer id чата
message_id
обязательный
Integer id сообщения бота
reply_markup
необязательный
InlineKeyboardMarkup Пусто — убрать кнопки
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/editMessageReplyMarkup" \
  -H 'Content-Type: application/json' \
  -d '{
    "chat_id": 7,
    "message_id": 777
  }'
Ответ — поле result
{
  "message_id": 777,
  "text": "Москва выбрана"
}

deleteMessage

GET · POST #
Возвращает True

Удалить сообщение у всех участников.

ПараметрТипОписание
chat_id
обязательный
Integer id чата
message_id
обязательный
Integer id сообщения
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/deleteMessage" \
  -H 'Content-Type: application/json' \
  -d '{
    "chat_id": 7,
    "message_id": 777
  }'
Ответ — поле result
true

sendChatAction

GET · POST #
Возвращает True

Показать «печатает…» — пока бот готовит ответ.

ПараметрТипОписание
chat_id
обязательный
Integer id чата
action
обязательный
String typing | upload_photo | upload_document
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/sendChatAction" \
  -H 'Content-Type: application/json' \
  -d '{
    "chat_id": 7,
    "action": "typing"
  }'
Ответ — поле result
true

Кнопки

answerCallbackQuery

GET · POST #
Возвращает True

Ответ на нажатие кнопки с callback_data. Пользователь видит текст всплывашкой (или окном при show_alert). Отвечайте в течение 5 секунд.

ПараметрТипОписание
callback_query_id
обязательный
String callback_query.id из обновления
text
необязательный
String До 200 символов
show_alert
необязательный
Boolean Окно вместо всплывашки
url
необязательный
String Открыть ссылку
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/answerCallbackQuery" \
  -H 'Content-Type: application/json' \
  -d '{
    "callback_query_id": "9b2e5c1a-…",
    "text": "Готово!"
  }'
Ответ — поле result
true

Профиль бота

setMyCommands

GET · POST #
Возвращает True

Команды — подсказки при вводе «/» и в кнопке «Меню».

ПараметрТипОписание
commands
обязательный
Array of BotCommand До 100 команд: command (a–z, 0–9, _) и description
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/setMyCommands" \
  -H 'Content-Type: application/json' \
  -d '{
    "commands": [
      {
        "command": "start",
        "description": "Начать"
      },
      {
        "command": "weather",
        "description": "Погода сейчас"
      }
    ]
  }'
Ответ — поле result
true

getMyCommands

GET · POST #
Возвращает Array of BotCommand

Текущие команды бота.

Без параметров.

curl "https://core.chatto.is/api/v1/bot/$TOKEN/getMyCommands"
Ответ — поле result
[
  {
    "command": "start",
    "description": "Начать"
  }
]

deleteMyCommands

GET · POST #
Возвращает True

Убрать все команды.

Без параметров.

curl "https://core.chatto.is/api/v1/bot/$TOKEN/deleteMyCommands"
Ответ — поле result
true

setMyName

GET · POST #
Возвращает True

Имя бота.

ПараметрТипОписание
name
обязательный
String До 64 символов
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/setMyName" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Погода"
  }'
Ответ — поле result
true

setMyDescription

GET · POST #
Возвращает True

«Что умеет этот бот?» — показывается в пустом чате перед «Запустить».

ПараметрТипОписание
description
необязательный
String До 512 символов
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/setMyDescription" \
  -H 'Content-Type: application/json' \
  -d '{
    "description": "Прогноз погоды на неделю для любого города"
  }'
Ответ — поле result
true

setMyShortDescription

GET · POST #
Возвращает True

Коротко о боте — в профиле и поиске.

ПараметрТипОписание
short_description
необязательный
String До 120 символов
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/setMyShortDescription" \
  -H 'Content-Type: application/json' \
  -d '{
    "short_description": "Погода в любом городе"
  }'
Ответ — поле result
true

setChatMenuButton

GET · POST #
Возвращает True

Кнопка слева от поля ввода: список команд или ваш веб-сайт.

ПараметрТипОписание
menu_button
обязательный
MenuButton {"type": "commands"} или {"type": "web_app", "text": "Открыть", "web_app": {"url": "https://…"}}
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/setChatMenuButton" \
  -H 'Content-Type: application/json' \
  -d '{
    "menu_button": {
      "type": "web_app",
      "text": "Открыть",
      "web_app": {
        "url": "https://example.com"
      }
    }
  }'
Ответ — поле result
true

getChatMenuButton

GET · POST #
Возвращает MenuButton

Текущая кнопка меню.

Без параметров.

curl "https://core.chatto.is/api/v1/bot/$TOKEN/getChatMenuButton"
Ответ — поле result
{
  "type": "web_app",
  "text": "Открыть",
  "web_app": {
    "url": "https://example.com"
  }
}

Mini Apps

setMainWebApp

GET · POST #
Возвращает True

Главное мини-приложение бота: кнопка «Открыть» в профиле и ссылки chatto.is/app/{бот}?startapp=…. Пустой url — убрать.

ПараметрТипОписание
url
необязательный
String HTTPS-адрес приложения
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/setMainWebApp" \
  -H 'Content-Type: application/json' \
  -d '{
    "url": "https://shop.example/app"
  }'
Ответ — поле result
true

answerWebAppQuery

GET · POST #
Возвращает SentWebAppMessage

Ответить на запрос мини-приложения: сообщение от бота придёт в чат с пользователем. query_id — из initData.

ПараметрТипОписание
web_app_query_id
обязательный
String query_id из initData
result
обязательный
InlineQueryResult {"type": "article", "id": "1", "title": "…", "input_message_content": {"message_text": "…"}, "reply_markup": {…}}
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/answerWebAppQuery" \
  -H 'Content-Type: application/json' \
  -d '{
    "web_app_query_id": "AAHdF6IQAAAAAN0XohDhrOrc",
    "result": {
      "type": "article",
      "id": "1",
      "title": "Заказ",
      "input_message_content": {
        "message_text": "Заказ №42 оформлен"
      }
    }
  }'
Ответ — поле result
{
  "inline_message_id": "1024"
}

validateWebAppData

GET · POST #
Возвращает Object

Проверить подпись initData на стороне Chatto — если не хочется считать HMAC самостоятельно. Подпись действительна 24 часа.

ПараметрТипОписание
init_data
обязательный
String Строка Chatto.WebApp.initData, как есть
curl -X POST "https://core.chatto.is/api/v1/bot/$TOKEN/validateWebAppData" \
  -H 'Content-Type: application/json' \
  -d '{
    "init_data": "query_id=AAHd…&user=%7B%22id%22%3A7%7D&auth_date=1790000000&hash=c5f3…"
  }'
Ответ — поле result
{
  "valid": true,
  "data": {
    "query_id": "AAHd…",
    "user": {
      "id": 7,
      "first_name": "Анна"
    },
    "auth_date": "1790000000"
  }
}

Объекты

Поля, которые приходят в обновлениях и ответах.

Update

ПолеТипОписание
update_idIntegerВозрастающий идентификатор обновления
messageMessageНовое сообщение боту (или web_app_data из мини-приложения)
callback_queryCallbackQueryНажатие кнопки

Message

ПолеТипОписание
message_idIntegerИдентификатор сообщения
fromUserОтправитель
chatChatЧат
dateIntegerВремя отправки, Unix
edit_dateIntegerВремя изменения
textStringТекст
reply_to_messageMessageСообщение, на которое ответили (message_id, text)
reply_markupInlineKeyboardMarkupКнопки
web_app_dataWebAppDataДанные из мини-приложения

User

ПолеТипОписание
idIntegerИдентификатор пользователя
is_botBooleanЭто бот
first_nameStringИмя
usernameStringИмя пользователя без @
language_codeStringЯзык интерфейса

Chat

ПолеТипОписание
idIntegerИдентификатор чата — используйте как chat_id
typeStringprivate, group или channel
titleStringНазвание группы

CallbackQuery

ПолеТипОписание
idStringДля answerCallbackQuery
fromUserКто нажал
messageMessageСообщение с кнопкой
dataStringcallback_data кнопки

InlineKeyboardButton

ПолеТипОписание
textStringПодпись, до 64 символов
urlStringОткрыть ссылку
callback_dataStringДо 64 байт, придёт боту
web_appWebAppInfo{"url": "https://…"} — открыть мини-приложение

WebAppData

ПолеТипОписание
dataStringСтрока из Chatto.WebApp.sendData
button_textStringПодпись кнопки, если была

Ошибки

При ошибке приходит ok: false, код и описание.

КодКогда возникает
400Неверные параметры, чат не найден, бот не участник чата, некорректные кнопки
401Неверный или перевыпущенный токен
403Пользователь заблокировал бота
404Неизвестный метод
409getUpdates при активном вебхуке
429Слишком много запросов — повторите позже

Лимиты

ЧтоОграничение
Запросы к APIдо 30 в секунду на бота
Текст сообщениядо 4096 символов
Кнопкидо 10 рядов по 8 кнопок, callback_data до 64 байт
Ответ на нажатие кнопки5 секунд
Ботов на аккаунтдо 20
Повторы вебхукадо 5 попыток: через 5 с, 30 с, 2 мин, 10 мин
Подпись initDataдействительна 24 часа

Примеры ботов

Готовые заготовки — подставьте токен и запустите.

Python — эхо-бот на long polling
import requests

BASE = "https://core.chatto.is/api/v1"
TOKEN = "123:AbC..."
api = lambda m, **p: requests.post(
    f"{BASE}/bot/{TOKEN}/{m}", json=p, timeout=35).json()

offset = 0
while True:
    for u in api("getUpdates", offset=offset, timeout=25)["result"]:
        offset = u["update_id"] + 1
        msg = u.get("message")
        if msg:
            api("sendMessage", chat_id=msg["chat"]["id"],
                text="Вы написали: " + (msg.get("text") or ""))
Node.js — вебхук с кнопками (Express)
import express from 'express';
const BASE = 'https://core.chatto.is/api/v1', TOKEN = '123:AbC...';
const api = (m, body) => fetch(`${BASE}/bot/${TOKEN}/${m}`, {
  method: 'POST', headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify(body) });

const app = express().use(express.json());
app.post('/bot', async (req, res) => {
  if (req.get('X-Chatto-Bot-Api-Secret-Token') !== 's3cret') return res.sendStatus(403);
  const { message, callback_query: q } = req.body;
  if (message) await api('sendMessage', { chat_id: message.chat.id, text: 'Как дела?',
    reply_markup: { inline_keyboard: [[{ text: 'Отлично', callback_data: 'ok' }]] } });
  if (q) await api('answerCallbackQuery', { callback_query_id: q.id, text: 'Принято' });
  res.sendStatus(200);
});
app.listen(3000);