Quick wins for a faster PC:
Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Clear out junk files and repair common Windows errorsFree Scan →Scan for outdated or missing drivers - takes under a minuteDriver Scan →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
Use Telegram’s getUpdates method to run a bot from a local PHP CLI process without exposing a public webhook endpoint. The process makes outbound HTTPS requests, waits for updates, handles each update, and advances an offset so Telegram confirms updates already received. This tutorial uses PHP cURL and defensive response handling; the code is an implementation example, not a tested deployment.
How does Telegram long polling work?
Telegram offers two mutually exclusive ways to deliver bot updates: long polling with getUpdates, where your process asks Telegram for updates, and webhooks with setWebhook, where Telegram sends updates to your HTTPS URL. For local development without a publicly reachable endpoint, polling is the straightforward fit: your machine initiates outbound HTTPS requests to the Bot API.
Telegram describes getUpdates as the method for receiving updates using long polling. Its timeout parameter is measured in seconds. The default is zero, which produces short polling; Telegram says that mode should only be used for testing. Set a positive timeout so the request can wait for updates rather than repeatedly checking immediately. See the live Telegram Bot API documentation for current method parameters and update types; the API reference may change over time.
A webhook is a different setup: Telegram must be able to reach a configured HTTPS URL. Telegram currently lists webhook ports 443, 80, 88, and 8443, with certificate and host requirements described in its Bots FAQ. Polling avoids that inbound endpoint requirement, but it does not eliminate the need for your local process to reach Telegram over the network.
#1 Best Overall
What do you need before running the PHP bot?
- A bot token created through Telegram’s
@BotFatherflow, described in the Bots FAQ. - PHP CLI with the cURL extension enabled. The PHP cURL examples document the request workflow using
curl_init(),curl_setopt(), andcurl_exec(). - Network access from the local machine to Telegram’s Bot API over HTTPS.
Keep the token outside committed source code. It appears in the Bot API endpoint path, so avoid printing or logging request URLs. For a local shell session, provide it as an environment variable rather than embedding it in the script.
How do you implement getUpdates in PHP?
Save the following as bot.php. It reads the token from the TELEGRAM_BOT_TOKEN environment variable, calls the Bot API with query parameters, checks cURL and HTTP errors, validates the JSON response, processes message updates, and only advances the offset after a handler completes without throwing an exception.
Rank #2
<?php
declare(strict_types=1);
$token = getenv('TELEGRAM_BOT_TOKEN');
if ($token === false || $token === '') {
fwrite(STDERR, "Set TELEGRAM_BOT_TOKEN before starting the bot.n");
exit(1);
}
$apiBase = 'https://api.telegram.org/bot' . $token . '/';
$offset = 0;
$longPollSeconds = 30;
/** Make one Bot API request and return its decoded JSON object. */
function telegramRequest(string $url, int $longPollSeconds): array
{
$ch = curl_init($url);
if ($ch === false) {
throw new RuntimeException('Could not initialize cURL.');
}
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => 5,
// Must exceed the Telegram long-poll wait, with room for network delay.
CURLOPT_TIMEOUT => $longPollSeconds + 15,
]);
$body = curl_exec($ch);
if ($body === false) {
$error = curl_error($ch);
curl_close($ch);
throw new RuntimeException('Telegram request failed: ' . $error);
}
$status = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($status < 200 || $status >= 300) {
throw new RuntimeException('Telegram returned HTTP status ' . $status);
}
try {
$result = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
} catch (JsonException $e) {
throw new RuntimeException('Telegram returned invalid JSON.', 0, $e);
}
if (!is_array($result) || ($result['ok'] ?? false) !== true || !isset($result['result']) || !is_array($result['result'])) {
$description = is_array($result) ? ($result['description'] ?? 'Unexpected Bot API response.') : 'Unexpected Bot API response.';
throw new RuntimeException((string) $description);
}
return $result;
}
/** Replace this with your application logic. Throw if processing did not succeed. */
function handleUpdate(array $update): void
{
if (isset($update['message']) && is_array($update['message'])) {
$message = $update['message'];
$text = $message['text'] ?? '';
// Add application logic here. Do not assume every message has text.
if (is_string($text)) {
fwrite(STDOUT, "Received a text message.n");
}
}
}
while (true) {
try {
$query = http_build_query([
'offset' => $offset,
'timeout' => $longPollSeconds,
'limit' => 100,
]);
$response = telegramRequest($apiBase . 'getUpdates?' . $query, $longPollSeconds);
foreach ($response['result'] as $update) {
if (!is_array($update) || !isset($update['update_id']) || !is_int($update['update_id'])) {
fwrite(STDERR, "Skipping an update with an invalid shape.n");
continue;
}
try {
handleUpdate($update);
} catch (Throwable $e) {
// Do not move the offset past a failed update; it can be returned again.
fwrite(STDERR, 'Update processing failed: ' . $e->getMessage() . "n");
break;
}
$offset = $update['update_id'] + 1;
}
} catch (Throwable $e) {
// Keep the loop alive for transient request failures; avoid a tight retry loop.
fwrite(STDERR, 'Polling error: ' . $e->getMessage() . "n");
sleep(2);
}
}
The 5-second connect timeout and the total timeout are illustrative settings, not universal requirements. Telegram’s official PHP HelloBot sample uses a 5-second cURL connect timeout and a 60-second total timeout. In this example, the total timeout is set to the long-poll wait plus 15 seconds; choose a margin that suits your network and ensure the HTTP client does not time out before Telegram’s wait ends. The PHP manual also shows cURL initialization, request options, execution, and error checks.
How do you start the local polling process?
- In a terminal, set the token for the current shell session:
export TELEGRAM_BOT_TOKEN='your-token'. Avoid sharing the terminal output or shell history containing a real token. - From the directory containing
bot.php, start PHP CLI:php bot.php. - Send a message to the bot in Telegram. The example prints a short notice when it receives a text message; put the actual reply or other application behavior inside
handleUpdate(). - Stop the process with your terminal’s interrupt command when finished. Let an outstanding long-poll request return if convenient; this example does not install special signal handlers.
Why is Telegram returning the same updates again?
Updates are confirmed when a later getUpdates request uses an offset higher than their update_id. Telegram’s FAQ explains that updates with IDs less than or equal to the offset are marked confirmed and will no longer be returned. Recalculate the offset from received updates and pass it on the next request; using update_id + 1 confirms that update.
The sample advances the offset after each successful handler call, so a processing exception leaves that update eligible to be returned again. This favors retrying over silently confirming work that failed, but it means your handler should be designed for possible repeated processing if it performs side effects. If a process stops after doing work but before sending the next offset, Telegram can deliver that update again.
What if getUpdates returns no updates or fails?
- An existing webhook is configured:
getUpdateswill not work while a webhook is set. Check the current state withgetWebhookInfo, then remove the webhook usingdeleteWebhookbefore polling. The methods and behavior are documented in the Bot API reference. - The token or connection is wrong: confirm the token is the one for this bot and that the local machine can make outbound HTTPS requests. The code reports transport errors, non-success HTTP status codes, malformed JSON, and Bot API errors to standard error.
- Expected update types are missing: inspect the
allowed_updatessetting. It controls which update types are delivered. An empty list includes all types exceptchat_member,message_reaction, andmessage_reaction_count; when omitted, Telegram reuses the previous setting. A changed setting does not affect updates created before that call. Consult the live Bot API documentation for current details. - The process was offline too long: Telegram retains incoming updates until received, but no longer than 24 hours. The
getUpdatesbatch limit is 1–100 updates per call and defaults to 100.
How much does getUpdates return at a time?
The limit parameter accepts 1 to 100 updates and defaults to 100, according to the Telegram Bot API reference. The example explicitly requests 100. If a response contains a batch, process its updates and carry the advanced offset into the next call so already handled updates are confirmed.
Quick Recap
Rank #4
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

