Getting started
First request: getMe
First request to the Bot API: the getMe method for token verification. Analyzing the response, common errors, and how to view the result in the terminal.
The Bot API base URL is https://api.telegram.org/bot<TOKEN>/<METHOD>. The safest "ping" is the getMe method: it does not send messages to users, requires no chat_id, and immediately shows whether the token is valid and what the bot's username is. This is the first request you should make right after getting a token from @BotFather.
Using the function from the previous chapter
In chapter BotFather и токен, we wrote the telegramApi() wrapper — here we simply call it. A brief reminder of the signature (full code is there):
<?php
// src/TelegramClient.php
function telegramApi(string $token, string $method, array $params = []): array
{
$url = 'https://api.telegram.org/bot' . $token . '/' . $method;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => $params !== [],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => $params === [] ? null : json_encode($params, JSON_UNESCAPED_UNICODE),
]);
$body = curl_exec($ch);
$code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
$err = curl_error($ch);
curl_close($ch);
if ($body === false) {
throw new RuntimeException('Network error: ' . $err);
}
$data = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('Invalid JSON: ' . json_last_error_msg());
}
if ($code >= 400 || empty($data['ok'])) {
throw new RuntimeException('Telegram error: ' . ($data['description'] ?? ('HTTP ' . $code)));
}
return $data['result'];
}
Calling getMe and inspecting the result
Create a first_request.php file next to TelegramClient.php. We get the token strictly from the environment — no hardcoding.
<?php
// first_request.php
require_once __DIR__ . '/src/TelegramClient.php';
$token = getenv('TELEGRAM_BOT_TOKEN');
if (!$token) {
fwrite(STDERR, "TELEGRAM_BOT_TOKEN не задан в окружении\n");
exit(1);
}
try {
$me = telegramApi($token, 'getMe');
// Успех — $me уже содержит result (массив User)
echo "OK\n";
// 1. Быстрый взгляд — var_dump
var_dump($me);
// 2. Красивый JSON для копирования в issue/лог
echo json_encode($me, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . "\n";
// 3. Доступ к отдельным полям
printf("Bot: @%s (id=%d)\n", $me['username'], $me['id']);
} catch (RuntimeException $e) {
fwrite(STDERR, 'FAIL: ' . $e->getMessage() . "\n");
exit(1);
}
Sample JSON response and field breakdown
Telegram returns a wrapper with ok and result. Our function has already unwrapped it and returned result. If we were looking at the raw response:
{
"ok": true,
"result": {
"id": 123456789,
"is_bot": true,
"first_name": "My Cool Bot",
"username": "mycoolbot",
"can_join_groups": true,
"can_read_all_group_messages": false,
"supports_inline_queries": false,
"can_connect_to_business": false,
"has_main_web_app": false
}
}
- ok: true — request succeeded;
resultcontains a User object. - id — unique numeric bot identifier (rarely needed, e.g., for deep-linking
tg://user?id=123456789). - username — public username without @, use in links like
https://t.me/mycoolbot. - first_name — display name, can be changed via BotFather (
/setname). - can_join_groups — whether the bot can be added to groups (setting
/setjoingroups). - can_read_all_group_messages — Privacy Mode:
false= the bot sees all group messages (setting/setprivacy). - supports_inline_queries — whether Inline Mode is enabled (
/setinline). - can_connect_to_business — whether the bot can connect to Business accounts.
- has_main_web_app — whether the bot has a configured Mini App (
/setmenubutton).
Common errors and how to read them
Telegram often returns HTTP 200 even on error — always check the ok field. Our function throws an exception if ok: false or HTTP ≥ 400.
{
"ok": false,
"error_code": 401,
"description": "Unauthorized"
}
- 401 Unauthorized — token is invalid, revoked via
/revoke, or contains unprintable characters (trailing space, BOM, newline). Check:var_dump($token)— length ~46 characters, format123456:ABC-DEF.... - 400 Bad Request — invalid method (typo in name) or malformed JSON in request body.
- 429 Too Many Requests — rate limit exceeded (30 req/s per token). The
Retry-Afterresponse header specifies the number of seconds to wait. Our client doesn't handle retries yet — we'll add this in chapter Production: очередь и retries. - Network error / curl error — no internet connection, DNS failure, or blocking by Roskomnadzor (requires a proxy/VPN on the server).
How to test in the terminal
$ export TELEGRAM_BOT_TOKEN=123456789:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw
$ php first_request.php
OK
array(8) {
["id"]=>
int(123456789)
["is_bot"]=>
bool(true)
["first_name"]=>
string(11) "My Cool Bot"
["username"]=>
string(10) "mycoolbot"
...
}
{
"id": 123456789,
"is_bot": true,
"first_name": "My Cool Bot",
"username": "mycoolbot",
...
}
Bot: @mycoolbot (id=123456789)
If you see FAIL: Unauthorized — check .env for BOM, quotes, or line breaks. getenv() will return false if the variable is not set. Make sure the token does not end up in git — add .env to .gitignore.
Next: получите апдейты через getUpdates and start processing user messages.