Отправка данных обратно в бот (sendData)

Отправишь данные из Mini App боту через sendData и обработаешь web_app_data на стороне бота.

sendData

Telegram.WebApp.sendData(data) закрывает Mini App и передаёт строку боту как служебное сообщение web_app_data. Работает только если приложение открыто из кнопки клавиатуры типа web_app. Из Menu Button, inline-кнопки или прямой ссылки t.me/... этот путь не подходит — там используй свой HTTPS API + initData.

Лимит строки — до 4096 байт.


Клиент sendData и бот принимает web_app_data

Сначала бот показывает keyboard с web_app:

typescript
// Bot API sendMessage + KeyboardButton web_app
const BOT_TOKEN = process.env.BOT_TOKEN!;

await fetch(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    chat_id: 123456789,
    text: "Выбери параметры в форме:",
    reply_markup: {
      keyboard: [
        [
          {
            text: "Открыть форму",
            web_app: { url: "https://app.example.com/form" },
          },
        ],
      ],
      resize_keyboard: true,
    },
  }),
});

В Mini App — сбор формы и sendData:

typescript
// Telegram WebApp sendData — только из keyboard web_app
// https://core.telegram.org/bots/webapps#initializing-mini-apps

const tg = window.Telegram.WebApp;
tg.ready();

type FormPayload = {
  city: string;
  seats: number;
};

function submitForm(payload: FormPayload): void {
  const data = JSON.stringify(payload);
  if (new TextEncoder().encode(data).length > 4096) {
    throw new Error("payload больше 4096 байт");
  }

  // После вызова Mini App закроется, бот получит web_app_data
  tg.sendData(data);
}

tg.MainButton.setText("Отправить");
tg.MainButton.show();
tg.MainButton.onClick(() => {
  submitForm({ city: "Berlin", seats: 2 });
});

Обработка на бэкенде бота (long polling / webhook):

typescript
// Входящий Update с message.web_app_data (Bot API)
type WebAppData = {
  data: string;
  button_text: string;
};

type Update = {
  message?: {
    chat: { id: number };
    web_app_data?: WebAppData;
  };
};

export async function handleUpdate(update: Update): Promise<void> {
  const webAppData = update.message?.web_app_data;
  if (!webAppData || !update.message) return;

  const payload = JSON.parse(webAppData.data) as {
    city: string;
    seats: number;
  };

  await fetch(`https://api.telegram.org/bot${process.env.BOT_TOKEN}/sendMessage`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      chat_id: update.message.chat.id,
      text: `Принято: ${payload.city}, мест: ${payload.seats}`,
    }),
  });
}

Как это работает

  • Keyboard web_app — единственный поддерживаемый контекст для sendData.
  • sendData(string) — Telegram закрывает WebView и кладёт строку в message.web_app_data.data.
  • Бот читает Update; отдельный HTTPS callback от фронта не нужен.
  • Для Menu Button / deep link — шлёшь initData на свой API, не sendData.

Частые ошибки

Вызываешь sendData из Menu Button → ничего полезного боту не придёт (или метод не сработает как ожидаешь). Открывай форму через keyboard web_app.

Шлёшь нестроковый объект → нужен JSON.stringify. Сырой object API не примет.

Кладёшь секреты в sendData → данные видны боту и проходят через Telegram. Для чувствительных операций — свой сервер + валидация initData.


Что дальше

Материалы gramdocs.tech носят образовательный характер и не являются финансовой, юридической или инвестиционной рекомендацией. Работа с блокчейном TON и токеном Gram связана с рисками потери средств. Правовая информация