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; result contains 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, format 123456: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-After response 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.