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
Build the bot as a set of separate steps: receive a Telegram update, authenticate and validate it, call Gemini from your server, then send a reply. Add bounded retries for temporary Gemini failures, an honest fallback when recovery fails, and a scheduler only for genuinely recurring tasks. Telegram delivery, Gemini requests, and scheduled jobs each have different failure modes; separating them makes those failures easier to handle without promising work the system cannot guarantee.
Choose how the bot will receive Telegram updates
Telegram’s Bot API is an HTTPS interface. Requests use a URL in the form https://api.telegram.org/bot<TOKEN>/METHOD_NAME and return JSON containing an ok value and, on failure, error details. Keep the bot token on the server; never embed it in a browser client, commit it to source control, or return it in a Telegram message. See the Telegram Bot API documentation.
Telegram supports two mutually exclusive update modes. Pick one for a bot deployment rather than trying to run both at once.
| Mode | How it works | When it fits | Important handling |
|---|---|---|---|
Long polling with getUpdates |
Your process requests updates from Telegram. A positive request timeout is appropriate; short polling is intended for testing. | You want to avoid configuring an inbound webhook endpoint and can keep a poller running. | Advance the offset beyond the highest handled update_id to confirm updates. Do not use it while an outgoing webhook is configured. |
Webhook with setWebhook |
Telegram sends JSON updates to your HTTPS endpoint. | Your deployment has a reachable HTTPS URL and push delivery suits the application. | Check the configured secret in the X-Telegram-Bot-Api-Secret-Token header. Return a successful 2xx response after successful handling; Telegram retries unsuccessful deliveries for a reasonable number of attempts, but does not specify a fixed count in this reference. |
The documentation does not establish that polling is universally faster or more reliable than webhooks. Whichever mode you choose, account for duplicate updates and monitor delivery lag or errors. Telegram retains incoming updates for no longer than 24 hours. Each update has a unique update_id, which is useful for deduplication and recovering order. For a webhook, persist processed IDs if repeating an action would cause harm; a process-local set is not a durable deduplication store.
#1 Best Overall
- Includes Raspberry Pi 5 with 2.4Ghz 64-bit quad-core CPU (8GB RAM)
- Includes 128GB Micro SD Card pre-loaded with 64-bit Raspberry Pi OS, USB MicroSD Card Reader
- CanaKit Turbine Black Case for the Raspberry Pi 5
- CanaKit Low Noise Bearing System Fan
- Mega Heat Sink - Black Anodized
Validate and route an update before calling Gemini
Handle only the update types and chat contexts your bot intends to support. For a basic text bot, check that a message exists, has a chat ID and contains text; ignore unsupported updates or reply with a brief instruction. Decide explicitly whether the bot responds in private chats, groups, or both. Do not send every update blindly to an AI service.
A webhook handler should reject a request with a missing or incorrect secret header before processing its body. After validating the update, use its update_id as an idempotency key before triggering non-idempotent side effects. The durable store and transaction strategy depend on your deployment; the key point is that a repeated delivery should not accidentally produce multiple replies or scheduled actions.
Call Gemini from the Node.js server
Google’s JavaScript integration uses the @google/genai SDK and the GoogleGenAI client. The API authenticates with an API key, sent as the x-goog-api-key header by the API; SDK usage handles the request path for you. Keep both the Gemini key and Telegram token in server-side configuration. Check the Gemini JavaScript setup and API reference for the current SDK, model, and endpoint options before deploying because these can change.
Rank #2
- Includes Raspberry Pi 4 4GB Model B with 1.5GHz 64-bit quad-core CPU (4GB RAM)
- Includes Pre-Loaded 32GB EVO+ Micro SD Card (Class 10), USB MicroSD Card Reader
- CanaKit Premium High-Gloss Raspberry Pi 4 Case with Integrated Fan Mount, CanaKit Low Noise Bearing System Fan
- CanaKit 3.5A USB-C Raspberry Pi 4 Power Supply (US Plug) with Noise Filter, Set of Heat Sinks, Display Cable - 6 foot (Supports up to 4K60p)
- CanaKit USB-C PiSwitch (On/Off Power Switch for Raspberry Pi 4)
For example, this is the shape of a server-side call using the SDK. Set GEMINI_MODEL to a model currently available to your project rather than hard-coding an assumption about model availability.
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
const model = process.env.GEMINI_MODEL;
async function generateReply(userText) {
if (!model) throw new Error("GEMINI_MODEL is not configured");
const result = await ai.models.generateContent({
model,
contents: userText,
});
return result.text;
}
A single API call does not define durable conversation history for your application. If the bot should remember earlier turns, decide what to store, how much context to send, how to limit its size, and how long to retain it. Telegram’s update and the SDK call do not choose a database or retention policy for you.
Retry temporary Gemini failures, not every error
A retry is useful only when repeating the request could plausibly succeed. Google’s troubleshooting guidance recommends exponential backoff with jitter, filtering for transient errors, and limiting attempts. Its examples identify 429, 408, and 5xx responses as retry candidates. The API error guide distinguishes request, authentication, permission, billing or credit, quota, and service errors.
| Failure class | Example response | Application response |
|---|---|---|
| Potentially transient | 408, 429, or 5xx | Retry a small, bounded number of times with exponential backoff and jitter. Stop when the limit is reached. |
| Request or configuration problem | 400 malformed request; 401 missing or invalid key; 403 permission failure | Do not immediately repeat the same request. Correct the payload, key, or permissions. |
| Billing or exhausted allowance | 402 depleted prepaid credits, or another quota or billing error | Surface the issue to operators and avoid an automatic retry loop. Check the applicable quota or billing state. |
The following illustrates one application policy: at most three total attempts for the listed transient status codes, with a randomized delay that grows between attempts. That count and delay are choices for this bot, not a universal Google requirement. Adapt status extraction to the error shape exposed by the SDK version you install.
Free tools Windows power users keep installed
One-click scans. No signup required.
function statusOf(error) {
return error?.status ?? error?.response?.status;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function withGeminiRetry(operation) {
const maxAttempts = 3;
for (let attempt = 1; ; attempt++) {
try {
return await operation();
} catch (error) {
const status = statusOf(error);
const transient = status === 408 || status === 429 || status >= 500;
if (!transient || attempt >= maxAttempts) throw error;
const baseMs = 500 * (2 ** (attempt - 1));
const jitterMs = Math.random() * 300;
await sleep(baseMs + jitterMs);
}
}
}
In a production handler, assign a correlation ID, record the error class, attempt count, and latency, then stop retrying when the policy is exhausted. Redact API keys, bot tokens, and sensitive message content from logs. If the request still fails, give the user a concise fallback, for example: “I can’t reach the AI service right now. Please try again shortly.” That message does not imply that the original request is queued.
If you want to answer later, persist the request in a durable queue and tell the user that the answer is pending only after it has actually been saved. The wording, retry count, queueing policy, and privacy controls are application decisions; the vendor documentation does not prescribe one universal fallback.
Rank #4
- Broadcom BCM2711, quad-core Cortex-A72 (ARM v8) 64-bit SoC @ 1. 5GHz
- 2. 4 GHz and 5. 0 GHz IEEE 802. 11b/g/n/ac wireless LAN, Bluetooth 5. 0, BLE
- 2 × USB 3. 0 ports, 2 x USB 2. 0 Ports
- 2 × micro HDMI ports supproting up to 4Kp60 video resolution
- Micro SD card slot for loading operating system and data storage
Send the response through Telegram
Once you have a reply—or a fallback—send it with Telegram’s sendMessage method. Check the API response’s ok field instead of treating any completed HTTP request as success. Keep message construction and delivery separate from Gemini generation so Telegram delivery errors can be logged and handled independently.
async function sendTelegramMessage(chatId, text) {
const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) throw new Error("TELEGRAM_BOT_TOKEN is not configured");
const response = await fetch(
`https://api.telegram.org/bot${token}/sendMessage`,
{
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ chat_id: chatId, text }),
},
);
const result = await response.json();
if (!response.ok || !result.ok) {
throw new Error(`Telegram sendMessage failed: ${result.description ?? response.status}`);
}
}
Telegram cautions that integer error-code contents may change, so avoid brittle logic that assumes a particular numeric error code will always mean the same thing. Use the documented response fields and retain enough non-secret context to diagnose failures.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchSchedule recurring work with node-cron
Use a scheduler for work that is genuinely recurring, such as a daily digest or cleanup. The current node-cron v4 API documents cron.schedule(expression, task, options); scheduling starts the task immediately. Specify an IANA timezone for human-facing schedules rather than relying on the server’s local timezone, especially when daylight-saving changes matter. See node-cron scheduling options.
Best Value
- Includes Raspberry Pi 5 16GB with 2.4Ghz 64-bit quad-core CPU (16GB RAM)
- Includes 128GB Micro SD Card pre-loaded with 64-bit Raspberry Pi OS, USB MicroSD Card Reader
- CanaKit Turbine Black Case for the Raspberry Pi 5
- CanaKit Low Noise Bearing System Fan
- Mega Heat Sink - Black Anodized
import cron from "node-cron";
cron.schedule(
"0 9 * * *", // 09:00 every day
async () => {
await sendDailyDigest();
},
{
name: "daily-digest",
timezone: "Etc/UTC",
noOverlap: true,
},
);
With noOverlap: true, node-cron skips a scheduled run if the previous run is still in progress; it does not queue the missed run. Decide whether skipping is acceptable for the job. A local in-process schedule is also not durable: a restart can interrupt work, and multiple app replicas can each run the same schedule.
When more than one instance runs
For fleet-wide jobs, node-cron documents distributed coordination. It requires a stable task name and either a designated runner configured through NODE_CRON_RUN or a shared run coordinator such as its documented Redis coordinator. Its distributed coordination documentation does not promise hard exactly-once execution under crashes or clock skew; make scheduled work safe to repeat.
If a task must survive restarts, needs durable retry policies or priorities, or requires stronger recovery semantics, use a durable queue or workflow system instead of relying on an in-process cron timer. Likewise, do not use an in-memory timer as a promise to retry a one-off failed Gemini request later.
Recommended Free Tools
Make failures observable and recoverable
Record enough operational information to distinguish Telegram delivery problems, Gemini failures, retry exhaustion, and scheduler issues. Do not log credentials or unnecessary user content. A practical checklist is:
- Store Telegram and Gemini credentials outside source control and redact them from logs.
- Choose one update mode; validate the webhook secret if using webhooks.
- Deduplicate updates before side effects that are unsafe to repeat.
- Retry only transient Gemini failures, with a cap and jitter; handle authentication, permission, malformed-request, billing, and quota problems separately.
- Keep fallback messages brief and honest about whether work is queued.
- Set the cron timezone explicitly and decide whether overlap-skipped runs are acceptable.
- For multiple replicas, coordinate fleet-wide schedules and make jobs idempotent.
- Monitor webhook pending updates and delivery errors, Gemini error classes and latency, scheduled-job successes and failures, overlap skips, and retry exhaustion.
These monitoring choices are an operational design recommendation, not a vendor-prescribed observability standard. The right database, hosting environment, retention period, and availability target depend on the bot’s requirements.
Quick Recap
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.

