Prevent duplicate processing in Telegram Serverless bots: webhook and idempotency checklist
Turn Telegram webhook retries and update_id behavior into testable requirements that prevent duplicate writes, rewards, orders, and stale updates.
A user taps once, but the bot registers twice, issues two rewards, or creates two orders. This is usually not a button problem. The system failed to treat redelivery of the same event as a normal condition.
Telegram retries a webhook when the request does not return a 2xx status. The official Bot API also says that update_id can identify repeated updates and help restore ordering. Webhooks and getUpdates are mutually exclusive delivery methods. A Serverless platform may hide URL, certificate, and scaling details, but the business logic must still define what happens during duplication, concurrency, and partial failure.
Redelivery is not the same as a second user action
One real action can follow this path:
- Telegram sends an update to the bot;
- the bot writes data or calls an external service;
- the process times out before returning success;
- Telegram considers delivery unsuccessful and sends the update again;
- a fresh instance executes the same logic.
If a reward was issued before the timeout and the second run does not check any record, the user receives it twice. The useful requirement is not “webhooks never duplicate.” It is “redelivery of one business event produces the same final result.”
Define an idempotency key first
Telegram's update_id is the most direct receive-layer deduplication key. Store completed identifiers and return success without repeating side effects when one reappears.
Business actions need stable keys of their own:
- registration: event identifier plus Telegram user identifier;
- voting: poll identifier plus user identifier, with a separate rule for vote changes;
- order: business order identifier;
- reward: campaign, user, and benefit type;
- scheduled reminder: reminder identifier plus scheduled occurrence.
A business key also covers separate updates that request the same action. Current timestamps and fresh random values are poor keys because every retry looks new.
Put side effects behind a durable state transition
For rewards, capacity, payments, or external notifications, store at least:
- the idempotency key;
- a received, processing, completed, or failed state;
- an input summary and creation time;
- the final result or upstream request identifier;
- whether a retry is safe or requires review.
The first request atomically creates a processing record. A concurrent request that sees the same key does not execute the side effect again. After completion, save the result so later duplicates can receive the same answer.
If an external service may have succeeded before timing out, do not call it again immediately. Query it with the original request identifier. If the result cannot be established, move the job to a review state rather than risking a duplicate charge or reward.
Decide when Telegram receives success
Telegram retries non-2xx webhook responses. Returning “complete” before the result is durably recorded can lose work, while holding a request open for a long job creates timeout risk.
A common minimal path is:
- validate the request and input;
- persist a job with a stable key;
- confirm that the job is durably accepted;
- return success;
- let a later worker complete it under the same idempotency rule.
If the selected Serverless runtime has no background-job or queue capability, narrow the first release to work that can finish within the request window. Do not assume arbitrary queue packages or a permanently running process are available.
Webhook authentication and idempotency solve different problems
Telegram's setWebhook accepts a secret_token. Telegram then includes it in the X-Telegram-Bot-Api-Secret-Token request header, helping the receiver verify that the request came through the webhook it configured. The hosted Bot API also requires HTTPS and supports a defined set of ports.
Authentication does not replace idempotency: a legitimate Telegram retry can still repeat. Idempotency does not replace authentication: an attacker may manufacture requests with different identifiers. Both matter, although a hosted Serverless platform may manage part of this transport. Check its contract before duplicating configuration or exposing secrets in bot logic.
A requirement you can adapt
Ensure that each Telegram update produces a business side effect at most once. Prefer a stable update identifier for delivery-layer deduplication and define a separate business idempotency key for registration, rewards, or orders. The first attempt stores a processing record and completion stores a reusable result. Concurrent attempts or retries must not consume capacity, issue a reward, or create an order again. If an external call times out with an unknown result, mark it for review instead of retrying blindly. Read-only help and query responses may be recomputed safely. Logs must not contain the bot token, webhook secret, or sensitive user content. If the platform abstracts webhook configuration, preserve the business idempotency rules without requiring custom URLs, certificates, or arbitrary external queues.
Test failures, not just the happy path
- Submitting the same
update_idtwice produces one business record. - Two concurrent requests with the same business key allow only one side-effecting transition.
- A retry after data was stored but the response timed out returns the saved result.
- An upstream timeout with unknown status does not trigger an automatic duplicate call.
- A bot restart does not forget completed idempotency keys.
- A request with invalid origin evidence or a wrong secret never reaches business processing.
- An older update arriving out of order cannot replace a newer terminal state.
- Recomputing a side-effect-free help or query response remains safe and understandable.
BotFatherV2 relevance and limits
BotFatherV2 supports creating and modifying bots through AI conversation and importing existing Telegram Serverless bots. The duplicate-delivery and failure cases above can be included in the requirement, then checked against the generated data model and real behavior.
BotFatherV2 is independent and is not affiliated with Telegram's official BotFather. This article does not mean that users must configure their own webhook, or that the current runtime provides an arbitrary queue, transactional database, or external dependency. The initial fixed SDK excludes arbitrary npm packages and Node/Bun APIs. Use only documented platform data and runtime capabilities, and verify the latest documentation, validation report, and real interactions.
Sources and verification date
- Telegram, Marvin's Marvellous Guide to All Things Webhook, official English technical guide; no publication date displayed. Checked October 12, 2026.
- Telegram, Telegram Bot API, official English documentation covering
update_id, webhook retries, andsecret_token. Checked October 12, 2026. - BitBear Studio, BotFatherV2, Build with AI, English product documentation; no publication date displayed. Checked October 12, 2026.