Commands & deep links
Deep links
We study the work with deep links in the Telegram Bot API in PHP. Analysis of start and startgroup parameters, payload parsing, referral systems and links for Mini Apps.
Deep links (deep links) is a special format of links to the Telegram bot that allows you to transfer additional parameters to it at startup. Link of the form https://t.me/username_bot?start=payload opens the bot and passes the string payload Faith in the team Products /. This is a key tool for tracking traffic sources, referral systems, integrating with websites and transmitting context (for example, product ID or promo code).
Types of deep links
Telegram supports two main types of deep links depending on where the bot should be launched:
- start — opens a personal chat with the bot. The user sees the "Start" (or "Start") button. After clicking, the bot receives a command
/start payloadin a private chat. Example link:https://t.me/my_bot?start=ref123. - startgroup — invites the user to add the bot to one of their groups. After selecting a group and adding a bot, it receives a command
/start payloaddirectly in the group chat. Example link:https://t.me/my_bot?startgroup=admin_setup.
Payload limits: the string must consist of Latin characters only (A-Z, a) zdigits)0-9), underscores _ and hyphen -. Maximum length is 64 characters. If you need to pass more complex data or a long string, use base64url encoding or keep matching payload → data in your server database.
How Telegram delivers payload
When a user clicks on a link and clicks the launch button, Telegram does not send a get request to your server directly. Instead, it generates a standard Update of type message, where in the field text the command is passed along with your parameter through a space: /start payload.
Example of a JSON update that will come to your webhook when you click on a link 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"
}
]
}
}Let's take a look at the structure of this JSON. Field Message text contains a string "/start ref_42". Pay attention to the array entities: type object bot_command has a length of 6 (this is the length of the word Products /). Anything after the sixth character and space (starting with index 7) is your payload. Field chat.id contains a unique user ID, which we will discuss in detail in the next chapter chat_id и user_id.
Command parsing and payload in PHP
Using the function parseCommand()which we did in chapter Команды /start, /help. Here we call it to extract arguments from the message text.
<?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"]);
}
}
}Example: Referral System
To implement the referral system, we need to generate a unique link for the user, and when a new user clicks on this link, we need to accrue a bonus to the inviter.
Using the function telegramApi()which we did in chapter Первый запрос: getMe. It sends HTTP requests to the Telegram API via 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
]);
}After calling the method SendMessage The API will return a JSON response. Be sure to check the field ok. If it is equal to trueRequest completed successfully
{
"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"
}
}Validation and transfer of complex data
The user can manually change the parameter in the address bar, so payload cannot be trusted directly. Always validate incoming data. If you need to transfer an array of data (for example, category ID and product ID), encode them in base64url format.
Standard base64 contains characters + And /that are prohibited in deep links Telegram, as well as the symbol = for addition. The function below securely encodes and decodes such parameters.
<?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 for Mini Apps
If you are developing a Mini App (more about them in chapter Что такое Mini App), you can use the startapp instead start. The link will look like this: https://t.me/my_bot/appname?startapp=payload.
This parameter does not send a text message to the bot. Instead, it is passed directly to the Mini App when it is initialized. You will be able to read it on the client via JavaScript in the object Telegram.WebApp.initDataUnsafe.start_param or on the data validation backend (see chapter Проверка 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=eyJpdGVtX2lkIjo3NzcsImRpc2NvdW50IjoxMH0How to debug deep links
To debug deep links, you need to see raw updates coming from Telegram. The easiest way is to write incoming requests to a log file on your server.
Add a file entry to the beginning of your PHP handler:
<?php
$rawInput = file_get_contents("php://input");
if ($rawInput) {
file_put_contents(__DIR__ . "/bot_debug.log", $rawInput . PHP_EOL, FILE_APPEND);
}After that, follow your referral link in Telegram, click the launch button and open the file bot_debug.log. you will see the exact JSON structure that the Telegram server sent, and you can check whether your script extracts the payload correctly.