Telegram Webhook Secret-Token Checks and update_id Dedupe for Telegram→X Schedulers in 2026

By AutoX Editorial (gspteck) · Published 2026-10-05 · Last verified 2026-10-05

A Telegram bot that schedules X Posts has two front doors: the outbound X API calls everyone worries about, and the inbound Telegram webhook that receives /schedule, /approve, and /cancel commands. If that inbound endpoint accepts forged requests, anyone who finds the URL can queue Posts on your account. If it processes a redelivered update twice, one approval can turn into two scheduled Posts. Telegram’s Bot API documents the tools to handle both: an optional secret_token that Telegram echoes back in a request header, and a sequential update_id meant for ignoring repeated updates. This guide covers how to use them in a Telegram→X scheduler like the ones discussed on AutoX. It complements our pieces on outbound create-Post idempotency and approval gates and token hygiene, and it does not repeat them. It is engineering hygiene, not a growth promise.

What Telegram actually documents about webhooks

Everything below comes from Telegram’s own pages, and you should re-check them before shipping because the Bot API changes often:

Inbound Telegram webhook flow: request arrives, secret-token header checked, update_id claimed, job enqueued and 200 returned
Verify the header, claim the update, enqueue the work, and only then return 200. The slow X API call runs in a worker, not inside the webhook request.

Verify the secret-token header before parsing anything

A webhook URL is not a secret. It shows up in logs, reverse-proxy configs, and sometimes in screenshots. The secret token is the part that proves Telegram sent the request. A practical pattern:

  1. Generate a high-entropy token using only the allowed character set, for example 64 URL-safe characters from a CSPRNG. Store it in your secret manager next to the bot token, never in source control. Pass it to setWebhook as secret_token.
  2. Check the header first. Before you parse JSON, touch your database, or log the body, read X-Telegram-Bot-Api-Secret-Token. If it is missing or wrong, return 401 or 403 with an empty body. Rejecting early keeps forged traffic from costing you database reads or X API calls.
  3. Compare in constant time. Use hmac.compare_digest in Python or crypto.timingSafeEqual in Node.js, not ==. Note that Node’s function throws when the buffers have different lengths, so check the length first or compare fixed-length digests of both values.
  4. Log carefully. Record that a rejection happened, with timestamp, source IP, and path. Never log the header value you received or the expected one.
  5. Rotate on purpose. When you rotate, call setWebhook with the new token and accept either the old or the new value for a short window. Telegram may still be retrying updates it signed with the old one.

The secret token does not replace your bot’s own authorization rules. A request can be genuinely from Telegram and still come from a user who should not be able to schedule Posts. Keep the operator allowlist and the approval gate from approval gates and API token hygiene in place. Subnet allowlisting at the edge is a reasonable extra layer, but Telegram publishes those ranges as current requirements, not permanent guarantees, so do not make it your only check.

Reject requests with a missing or mismatched secret-token header; accept only matching headers compared in constant time
Reject early with an empty 401/403. Accept only when the header matches under a constant-time comparison and the body parses to an update type you subscribed to.

Dedupe on update_id so one command acts once

Retries are where a Telegram→X scheduler goes wrong. Say the /approve handler calls the X API inline, X is slow, the request runs longer than Telegram is willing to wait, and Telegram redelivers. The naïve handler approves the same draft twice, and now there are two scheduled Posts. Here is how to prevent that:

Redelivery scenario: slow handler causes Telegram to resend the same update_id; dedupe claim prevents a second scheduled Post
A slow handler leads Telegram to resend the same update_id. A durable claim turns the second delivery into a no-op instead of a second scheduled Post.

Narrow the surface with allowed_updates and watch getWebhookInfo

Two more Bot API settings deserve a minute of your time:

Bot-side scheduling still has to respect X-side limits. Pair this with rate-limit and credit budgets and dead-letter and 429 backoff so a burst of valid commands does not become a burst of rejected Posts.

Webhook hardening checklist: secret_token, constant-time compare, update_id claim, ack fast, allowed_updates, getWebhookInfo monitoring
Six controls that keep the inbound side of a Telegram→X scheduler safe from forgery and double-processing.

A minimal handler shape (pseudocode)

on POST /telegram/webhook:
  got = header("X-Telegram-Bot-Api-Secret-Token") or ""
  if not constant_time_equal(got, CURRENT) and not constant_time_equal(got, PREVIOUS_DURING_ROTATION):
      return 403            # empty body, log the event without values
  update = parse_json(body)
  if not create_if_absent("tg_updates/" + BOT_ID + ":" + update.update_id, ttl=72h):
      return 200            # already handled
  enqueue(job_from(update))  # X API work happens in a worker
  return 200

This is a shape, not a library. Adapt it to your framework, and keep the bot token and the secret token in a secret manager, as covered in secret storage for long-lived bots.

Practical checklist

Key takeaways

Telegram Bot API parameters, header names, and network requirements summarized here come from Telegram’s public documentation as of 2026-10-05 and can change. Confirm them on core.telegram.org before relying on them. No affiliate links. Last verified 2026-10-05.