Users & chats

Groups

We study working with groups and supergroups in Telegram in PHP. We analyze the receipt of chat_id, rights management, ban, mut and the creation of a verification system for new participants.

A Telegram group is a group chat that can be a regular group (legacy format up to 200 participants) or a supergroup with a capacity of up to 200,000 users. For the developer, the difference between them is fundamental: supergroups have an identifier chat_id always starts with a prefix -100 such as -1001234567890), advanced administrator rights, message pinning, slow mode, history for new members, and topic segregation (forums) are available.

In the Bot API, in 99% of cases, you will work with supergroups, since ordinary groups automatically migrate to supergroups when the chat grows or the publicity settings change. Field message.chat.type in such chats, returns the value supergroup.

Group types and how to distinguish them in JSON

When updates are received (via Webhook or Long Polling), the chat type is passed in the object Chat. Here is an example of a JSON response when a user sends a message to a supergroup:

{
"ok": true,
"result": [
{
"update_id": 54321098,
"message": {
"message_id": 1024,
"date": 1710000000,
"chat": {
"id": -1001987654321,
"type": "supergroup",
"title": "PHP Backend Developers",
"username": "php_backend_chat",
"is_forum": false
},
"from": {
"id": 987654321,
"is_bot": false,
"first_name": "Сергей",
"username": "sergey_php"
},
"text": "Всем привет! Как правильно банить юзеров через API?"
}
}
]
}

When analyzing incoming JSON, pay attention to the following fields:

  • chat.id — a unique 64-bit chat ID. For supergroups, it is always negative and begins with -100.
  • chat.type — contains a string supergroup or group (for old legacy groups).
  • chat.is_forum Returns true, if topics (sections) are included in the supergroup. In this case, the messages will contain an additional field message_thread_id.
  • chat.username — public username of the group (if set). Private groups do not have this field.

Adding a bot to a group and the first event

The bot cannot join the group on its own — it must be invited by a user who has the rights to do so. At the time of adding the bot, Telegram sends an update with the field new_chat_members. This is the perfect entry point to capture the bot's appearance in the new chat, save chat_id to the database and send a welcome message.

Using the function telegramApi()which we did in chapter Первый запрос: getMe. Here we only call it — we do not copy the implementation.

<?php
// Предполагаем, что $update получен через Webhook или Long Polling
$update = json_decode(file_get_contents('php://input'), true);

if (!empty($update['message']['new_chat_members'])) {
foreach ($update['message']['new_chat_members'] as $newMember) {
// Проверяем, что добавленный участник — это наш бот
// Для этого можно сравнить username или ID бота, полученный ранее из getMe
if ($newMember['is_bot'] === true && $newMember['username'] === 'MyHelperBot') {
$chatId = $update['message']['chat']['id'];
$chatTitle = $update['message']['chat']['title'];

// Здесь должна быть запись в вашу БД:
// $db->saveChat($chatId, $chatTitle);

telegramApi('sendMessage', [
'chat_id' => $chatId,
'text' => "Привет, чат *" . htmlspecialchars($chatTitle) . "*! 👋\nЯ готов к работе. Сделайте меня администратором, чтобы я мог модерировать сообщения.",
'parse_mode' => 'Markdown'
]);
}
}
}

Admin rights: what you need for moderation

By default, an ordinary member of a group (including a bot) cannot influence other users. In order for the bot to delete spam, ban intruders, or pin important messages, the group owner must be assigned as an administrator and given the appropriate permissions:

  • can_delete_messages — the right to delete other people's messages (method deleteMessage).
  • can_restrict_members — the right to ban, ban and restrict users (methods banChatMember, restrictChatMember).
  • can_pin_messages — the right to fix messages (method pinChatMessage).

Before performing any moderation action, it is recommended to check whether the bot has the necessary rights in a particular chat. The bot status is used for this.

Using the function getBotStatusInChat()which we did in chapter chat_id и user_id. Here we only call it — we do not copy the implementation.

<?php
$chatId = -1001987654321;
$botStatus = getBotStatusInChat($chatId);

if ($botStatus && $botStatus['status'] === 'administrator') {
if (!empty($botStatus['can_restrict_members'])) {
echo "Бот является администратором и может управлять пользователями.\n";
} else {
echo "Бот админ, но у него нет права restrict_members!\n";
}
} else {
echo "Бот не является администратором в этом чате.\n";
}

When calling the method getChatMember for the Telegram administrator returns a detailed object with rights. Sample API JSON response:

{
"ok": true,
"result": {
"user": {
"id": 123456789,
"is_bot": true,
"first_name": "MyHelperBot",
"username": "MyHelperBot"
},
"status": "administrator",
"can_be_edited": false,
"can_manage_chat": true,
"can_change_info": false,
"can_post_messages": false,
"can_edit_messages": false,
"can_delete_messages": true,
"can_invite_users": true,
"can_restrict_members": true,
"can_pin_messages": true,
"can_manage_topics": false
}
}

Important limitation: The bot will never be able to apply sanctions (ban, mut) to the creator of the group (owner) or to administrators who are above him in the hierarchy. If you try to do this, the API will return an error 400 bad request: CHAT_admin_requested or can't restrict member. Always handle such errors in the code.

Ban, Mut, and Rasban: Case Studies

Bot API uses three key methods to manage user restrictions:

  1. banChatMember — completely removes the user from the group. He won't be able to come back on his own until he's unscrewed.
  2. restrictChatMember — imposes partial restrictions (prohibition to write, send media, links).
  3. unbanChatMember — removes the ban or restrictions.

Using the function telegramApi()which we did in chapter Первый запрос: getMe. Here we only call it — we do not copy the implementation.

<?php
$chatId = -1001987654321;
$userId = 987654321;

// 1. Полный бан пользователя на 7 дней (передаем Unix timestamp)
$banDuration = time() + (7 * 24 * 3600);
$banResult = telegramApi('banChatMember', [
'chat_id' => $chatId,
'user_id' => $userId,
'until_date' => $banDuration
]);

if ($banResult && $banResult['ok']) {
echo "Пользователь успешно забанен на неделю.\n";
} else {
echo "Ошибка бана: " . ($banResult['description'] ?? 'Неизвестная ошибка') . "\n";
}

// 2. Мут пользователя (restrict) — запрещаем отправлять любые сообщения на 1 час
$muteDuration = time() + 3600;
$muteResult = telegramApi('restrictChatMember', [
'chat_id' => $chatId,
'user_id' => $userId,
'permissions' => json_encode([
'can_send_messages' => false,
'can_send_media_messages' => false,
'can_send_other_messages' => false,
'can_add_web_page_previews' => false
]),
'until_date' => $muteDuration
]);

// 3. Разбан (unban) — возвращает пользователю возможность войти в группу
$unbanResult = telegramApi('unbanChatMember', [
'chat_id' => $chatId,
'user_id' => $userId,
'only_if_banned' => true // Снимет бан, но не сбросит активный мут, если пользователь внутри чата
]);

Scenario: Welcome and Quarantine for Beginners

A popular way to protect against spambots is to put each new participant in read-only mode until they click the verification button below the welcome message.

Using the function telegramApi()which we did in chapter Первый запрос: getMe. Here we only call it — we do not copy the implementation.

<?php
$update = json_decode(file_get_contents('php://input'), true);

// Шаг 1: Ловим нового пользователя и отправляем в мут
if (!empty($update['message']['new_chat_members'])) {
foreach ($update['message']['new_chat_members'] as $newMember) {
if ($newMember['is_bot']) continue; // Ботов не трогаем (или сразу баним)

$chatId = $update['message']['chat']['id'];
$userId = $newMember['id'];
$userName = htmlspecialchars($newMember['first_name']);

// Ограничиваем права (запрещаем писать)
telegramApi('restrictChatMember', [
'chat_id' => $chatId,
'user_id' => $userId,
'permissions' => json_encode([
'can_send_messages' => false
])
]);

// Отправляем приветствие с inline-кнопкой
telegramApi(&039;sendMessage', [
'chat_id' => $chatId,
'text' => "Добро пожаловать, {$userName}! 🛡️\nЧтобы получить возможность писать в чат, подтвердите, что вы не бот.",
'reply_markup' => json_encode([
'inline_keyboard' => [[
[
'text' => '✅ Я человек',
'callback_data' => "verify:{$userId}"
]
]]
])
]);
}
}

// Шаг 2: Обрабатываем нажатие на кнопку верификации
if (!empty($update['callback_query'])) {
$callbackQuery = $update['callback_query'];
$data = $callbackQuery['data'];
$clickerId = $callbackQuery['from']['id'];
$chatId = $callbackQuery['message']['chat']['id'];
$messageId = $callbackQuery['message']['message_id'];

if (str_starts_with($data, 'verify:')) {
$targetUserId = (int)str_replace('verify:', '', $data);

// Проверяем, что кнопку нажал именно тот пользователь, который вступил
if ($clickerId !== $targetUserId) {
telegramApi('answerCallbackQuery', [
'callback_query_id' => $callbackQuery['id'],
'text' => '❌ Эта кнопка предназначена не для вас!',
'show_alert' => true
]);
exit;
}

// Возвращаем пользователю стандартные права
telegramApi('restrictChatMember', [
'chat_id' => $chatId,
'user_id' => $targetUserId,
'permissions' => json_encode([
'can_send_messages' => true,
'can_send_media_messages' => true,
'can_send_other_messages' => true,
'can_add_web_page_previews' => true
])
]);

// Уведомляем об успешном прохождении
telegramApi('answerCallbackQuery', [
'callback_query_id' => $callbackQuery['id'],
'text' => 'Доступ разрешен! Приятного общения.'
]);

// Удаляем приветственное сообщение, чтобы не засорять чат
telegramApi('deleteMessage', [
'chat_id' => $chatId,
'message_id' => $messageId
]);
}
}

Next: Каналы