Команды и deep links
Deep links
Изучаем работу с глубокими ссылками (deep links) в Telegram Bot API на PHP. Разбор параметров start и startgroup, парсинг payload, реферальные системы и ссылки для Mini Apps.
Deep links (глубокие ссылки) — это специальный формат ссылок на Telegram-бота, позволяющий передавать в него дополнительные параметры при запуске. Ссылка вида https://t.me/username_bot?start=payload открывает бота и передает строку payload в команду /start. Это ключевой инструмент для отслеживания источников трафика, реферальных систем, интеграции с сайтами и передачи контекста (например, ID товара или промокода).
Типы deep links
Telegram поддерживает два основных типа глубоких ссылок в зависимости от того, где должен быть запущен бот:
- start — открывает личный чат с ботом. Пользователь видит кнопку «Запустить» (или «Старт»). После нажатия бот получает команду
/start payloadв приватном чате. Пример ссылки:https://t.me/my_bot?start=ref123. - startgroup — предлагает пользователю добавить бота в одну из своих групп. После выбора группы и добавления бота, тот получает команду
/start payloadпрямо в групповом чате. Пример ссылки:https://t.me/my_bot?startgroup=admin_setup.
Ограничения на полезную нагрузку (payload): строка должна состоять только из символов латиницы (A-Z, a-z), цифр (0-9), подчеркивания _ и дефиса -. Максимальная длина — 64 символа. Если вам нужно передать более сложные данные или длинную строку, используйте кодирование в base64url или сохраняйте соответствие payload → данные в базе данных вашего сервера.
Как Telegram доставляет payload
Когда пользователь переходит по ссылке и нажимает кнопку запуска, Telegram не отправляет GET-запрос на ваш сервер напрямую. Вместо этого он генерирует стандартное обновление (Update) типа message, где в поле text передается команда вместе с вашим параметром через пробел: /start payload.
Пример JSON-обновления, которое придет на ваш вебхук при переходе по ссылке https://t.me/my_bot?start=ref_42:
{
"update_id": 987654321,
"message": {
"message_id": 105,
"from": {
"id": 123456789,
"is_bot": false,
"first_name": "Ivan",
"username": "ivan_dev"
},
"chat": {
"id": 123456789,
"first_name": "Ivan",
"username": "ivan_dev",
"type": "private"
},
"date": 1710000000,
"text": "/start ref_42",
"entities": [
{
"offset": 0,
"length": 6,
"type": "bot_command"
}
]
}
}Разберем структуру этого JSON. Поле message.text содержит строку "/start ref_42". Обратите внимание на массив entities: объект типа bot_command имеет длину 6 (это длина слова /start). Всё, что идет после шестого символа и пробела (начиная с индекса 7), является вашим payload. Поле chat.id содержит уникальный идентификатор пользователя, о котором мы подробно поговорим в следующей главе chat_id и user_id.
Парсинг команды и payload на PHP
Используем функцию parseCommand(), которую мы сделали в главе Команды /start, /help. Здесь мы вызываем её для извлечения аргументов из текста сообщения.
<?php
// Функция parseCommand импортирована из главы "Команды /start, /help"
// Ссылка на реализацию: /telegram-bot-api/commands
$update = json_decode(file_get_contents("php://input"), true);
$message = $update["message"] ?? null;
if ($message && isset($message["text"])) {
$cmd = parseCommand($message["text"]);
if ($cmd["command"] === "start") {
$payload = $cmd["args"]; // содержит "ref_42" или пустую строку
if ($payload !== "") {
// Обрабатываем глубокую ссылку
handleDeepLink($payload, $message);
} else {
// Обычный запуск бота без параметров
sendWelcome($message["chat"]["id"]);
}
}
}Пример: Реферальная система
Для реализации реферальной системы нам нужно сгенерировать уникальную ссылку для пользователя, а при переходе нового пользователя по этой ссылке — начислить бонус пригласителю.
Используем функцию telegramApi(), которую мы сделали в главе Первый запрос: getMe. Она отправляет HTTP-запросы к API Telegram через cURL.
<?php
// Функция telegramApi импортирована из главы "Первый запрос: getMe"
// Ссылка на реализацию: /telegram-bot-api/first-request
function buildRefLink(string $botUsername, int $userId): string {
return "https://t.me/" . $botUsername . "?start=ref_" . $userId;
}
function handleDeepLink(string $payload, array $message): void {
$chatId = $message["chat"]["id"];
$newUserId = $message["from"]["id"];
if (preg_match("/^ref_(\d+)$/", $payload, $matches)) {
$referrerId = (int)$matches[1];
if ($referrerId === $newUserId) {
$text = "Вы не можете зарегистрироваться по собственной реферальной ссылке!";
} else {
// Здесь должна быть логика сохранения реферала в базу данных
$text = "Добро пожаловать! Вы зарегистрировались по приглашению пользователя " . $referrerId;
}
} else {
$text = "Неизвестный параметр запуска.";
}
telegramApi("sendMessage", [
"chat_id" => $chatId,
"text" => $text
]);
}
function sendWelcome(int $chatId): void {
$botUsername = "my_sample_bot"; // В реальном коде лучше получить динамически через getMe
$refLink = buildRefLink($botUsername, $chatId);
telegramApi("sendMessage", [
"chat_id" => $chatId,
"text" => "Добро пожаловать в нашего бота! Ваша реферальная ссылка: " . $refLink
]);
}После вызова метода sendMessage API вернет JSON-ответ. Обязательно проверяйте поле ok. Если оно равно true, запрос выполнен успешно:
{
"ok": true,
"result": {
"message_id": 201,
"from": {
"id": 999999999,
"is_bot": true,
"first_name": "My Sample Bot",
"username": "my_sample_bot"
},
"chat": {
"id": 123456789,
"first_name": "Ivan",
"username": "ivan_dev",
"type": "private"
},
"date": 1710000005,
"text": "Добро пожаловать! Вы зарегистрировались по приглашению пользователя 42"
}
}Валидация и передача сложных данных
Пользователь может вручную изменить параметр в адресной строке, поэтому доверять payload напрямую нельзя. Всегда валидируйте входящие данные. Если вам нужно передать массив данных (например, ID категории и ID товара), закодируйте их в формат base64url.
Стандартный base64 содержит символы + и /, которые запрещены в deep links Telegram, а также символ = для дополнения. Функция ниже безопасно кодирует и декодирует такие параметры.
<?php
// Безопасное кодирование в base64url для Telegram deep links
function base64UrlEncode(string $data): string {
return rtrim(strtr(base64_encode($data), "+/", "-_"), "=");
}
// Декодирование base64url
function base64UrlDecode(string $data): string {
return base64_decode(strtr($data, "-_", "+/"));
}
function validateAndParsePayload(string $payload): ?array {
// Пример: ожидаем payload вида "prod_eyJpZCI6MTIzLCJjYXQiOiJib29rcyJ9" (prod_ + base64url)
if (!str_starts_with($payload, "prod_")) {
return null;
}
$encodedData = substr($payload, 5);
$decodedJson = base64UrlDecode($encodedData);
if (!$decodedJson) {
return null;
}
$data = json_decode($decodedJson, true);
if (json_last_error() !== JSON_ERROR_NONE || !isset($data["id"], $data["cat"])) {
return null;
}
return $data;
}Deep links для Mini Apps
Если вы разрабатываете Mini App (подробнее о них в главе Что такое Mini App), вы можете использовать параметр startapp вместо start. Ссылка будет выглядеть так: https://t.me/my_bot/appname?startapp=payload.
Этот параметр не отправляет текстовое сообщение боту. Вместо этого он передается напрямую в Mini App при его инициализации. Вы сможете прочитать его на клиенте через JavaScript в объекте Telegram.WebApp.initDataUnsafe.start_param или на бэкенде при валидации данных (см. главу Проверка initData).
<?php
// Пример генерации ссылки для Mini App с параметром startapp
function buildMiniAppLink(string $botUsername, string $appName, array $params): string {
$json = json_encode($params);
$payload = rtrim(strtr(base64_encode($json), "+/", "-_"), "=");
return "https://t.me/" . $botUsername . "/" . $appName . "?startapp=" . $payload;
}
// Пример использования:
$link = buildMiniAppLink("my_bot", "shop", ["item_id" => 777, "discount" => 10]);
// Результат: https://t.me/my_bot/shop?startapp=eyJpdGVtX2lkIjo3NzcsImRpc2NvdW50IjoxMH0Как отлаживать deep links
Для отладки deep-ссылок вам необходимо видеть сырые обновления, приходящие от Telegram. Самый простой способ — записывать входящие запросы в лог-файл на вашем сервере.
Добавьте в начало вашего PHP-обработчика запись в файл:
<?php
$rawInput = file_get_contents("php://input");
if ($rawInput) {
file_put_contents(__DIR__ . "/bot_debug.log", $rawInput . PHP_EOL, FILE_APPEND);
}После этого перейдите по вашей реферальной ссылке в Telegram, нажмите кнопку запуска и откройте файл bot_debug.log. Вы увидите точную структуру JSON, которую прислал сервер Telegram, и сможете проверить, правильно ли ваш скрипт извлекает payload.