Клавиатуры

callback_query

Разбираем callback_query: структура апдейта, обязательный answerCallbackQuery, обработка нажатий inline-кнопок и подводные камни (старый payload, лимит 64 байта, срок жизни).

Когда пользователь нажимает кнопку с callback_data, Telegram отправляет боту Update с полем callback_query. Это отдельный тип апдейта — он приходит вместо обычного message, поэтому хендлер должен различать оба варианта.

Структура callback_query

Ключевые поля:

  • id — уникальный ID нажатия, его нужно передать в answerCallbackQuery.
  • from — объект User, нажавший кнопку.
  • message — сообщение, к которому привязана клавиатура (содержит chat, message_id, text).
  • data — строка callback_data, которую вы положили в кнопку.
  • chat_instance — идентификатор сессии, пригодится для игр.

Если кнопка была в inline-режиме, вместо message придёт inline_message_id.

answerCallbackQuery

Обязательный вызов в течение ~30 секунд, иначе у пользователя останется «часики» на кнопке. Метод принимает:

  • callback_query_id — из апдейта.
  • text — короткое всплывающее уведомление (до 200 символов).
  • show_alert — если true, покажет модалку вместо тоста.
// Хендлер callback_query
if (isset($update['callback_query'])) {
    $cb = $update['callback_query'];
    $cbId   = $cb['id'];
    $data   = $cb['data'];          // например "take:ab12cd"
    $chatId = $cb['message']['chat']['id'];
    $msgId  = $cb['message']['message_id'];

    // 1) Снимаем «часики»
    telegramApi($token, 'answerCallbackQuery', [
        'callback_query_id' => $cbId,
        'text'              => 'Заявка взята в работу',
    ]);

    // 2) Разбираем действие
    [$action, $payload] = explode(':', $data, 2) + [null, null];

    if ($action === 'take') {
        // ... тут работа с БД по $payload ...

        // 3) Обновляем исходное сообщение
        telegramApi($token, 'editMessageReplyMarkup', [
            'chat_id'      => $chatId,
            'message_id'   => $msgId,
            'reply_markup' => ['inline_keyboard' => []],
        ]);
    }
}

Подводные камни

  • Срок жизни callback_query. Нажать кнопку можно только пока сообщение существует на экране. Удалили сообщение — нажатия не будет.
  • Один апдейт — одно нажатие. Если юзер быстро тапнул две кнопки, придут два отдельных callback_query.
  • Нельзя слать новое сообщение в ответ. Для ответа пользователю используйте sendMessage в нужный chat_id или answerCallbackQuery для тоста.
  • Устаревший payload. Если вы кладёте в callback_data id из БД — проверяйте, что запись ещё существует, иначе отвечайте text «Заявка уже обработана».

Что хранить в callback_data

64 байта — жёсткий лимит Telegram. Рабочая схема:

  1. Префикс действия (take, reject, page) + :.
  2. Короткий id из БД (hex от random_bytes(7) = 14 символов).
  3. Никаких JSON, кириллицы и сериализованных объектов.

Дальше: Reply Keyboard — обычные кнопки под полем ввода и их отличия от inline.