skip to Main Content

I’m writing a Telegram bot and I’m using the official bot API. I’ve got a webhook server that handles requests and sends a 200 OK response for every request.

Before the server stops, the webhook is detached so Telegram does not send updates anymore. However, whenever I turn the bot on and set the webhook URL again, Telegram starts flooding the webhook server with old updates.

Is there any way I can prevent this without requesting /getUpdates repeatedly until I reach the last update?

Here’s a heavily simplified version of how my code looks like:

var http = require('http'),
    unirest = require('unirest'),
    token = '***';

// Attach the webhook
unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
    .field('url', 'https://example.com/api/update')
    .end();

process.on('exit', function() {
    // Detach the webhook
    unirest.post('https://api.telegram.org/bot' + token + '/setWebhook')
        .field('url', '')
        .end();
});

// Handle requests
var server = http.createServer(function(req, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' })
    res.end('Thanks!');
});

server.listen(80);

Thanks in advance.

4

Answers


  1. When you server starts up you can record the timestamp and then use this to compare against incoming message date values. If the date is >= the timestamp when you started…the message is ok to be processed.

    I am not sure if there is a way you can tell Telegram you are only interested in new updates, their retry mechanism is a feature so that messages aren’t missed…even if your bot is offline.

    Login or Signup to reply.
  2. I have the same issue, then I tried to reset the default webhook with

    https://api.telegram.org/bot%5BmybotuniqueID%5D/setWebhook?url=

    after that, i verified the current getUpdates query were the same old updates but I sent new requests through the telegram’s bot chat

    https://api.telegram.org/bot%5BmybotuniqueID%5D/getUpdates

    when I set up my webhook again the webhook read the same old updates. Maybe the getUpdates method is not refreshing the JSON content.

    NOTE:
    in my case, it was working fine until I decided to change /set privacy bot settings from botfather

    Login or Signup to reply.
  3. In the webhook mode, Telegram servers send updates every minute until receives an OK response from the webhook program.
    so I recommend these steps:

    1. Check your webhook program that you specified its address as url parameter of the setWebhook method. Call its address in a browser. It does not produce an output to view, but clears that probably there is no error in your program.
    2. Include a command that produces a ‘200 OK Status’ header output in your program to assure that the program sends this header to the Telegram server.
    Login or Signup to reply.
  4. The best way is to use update_id which is a specific number that increases on every new request (i.e. update). How to implement it?

    First off, let’s start with the following anonymous class (using PHP7):

    $lastUpdateId = new class()
    {
        const FILE_PATH = "last-update-id.txt";
        private $value = 1;
    
        public function __construct()
        {
            $this->ensureFileExists();
            $this->value = filesize(self::FILE_PATH) == 0
                ? 0 : (int)(file_get_contents(self::FILE_PATH));
        }
    
        public function set(int $lastUpdateId)
        {
            $this->ensureFileExists();
            file_put_contents(self::FILE_PATH, $lastUpdateId);
            $this->value = $lastUpdateId;
        }
    
        public function get(): int
        {
            return $this->value;
        }
    
        public function isNewRequest(int $updateId): bool
        {
            return $updateId > $this->value;
        }
    
        private function ensureFileExists()
        {
            if (!file_exists(self::FILE_PATH)) {
                touch(self::FILE_PATH);
            }
        }
    };
    

    What the class does is clear: Handling the last update_id via a plain file.

    Note: The class is tried to be as short as possible. It does not provide error-checking. Use your custom implementation (e.g. use SplFileObject instead of file_{get|put}_contents() functions) instead.

    Now, there are two methods of getting updates: Long Polling xor WebHooks (check Telegram bot API for more details on each methods and all JSON properties). The above code (or similar) should be used in both cases.

    Note: Currently, it is impossible to use both methods at the same time.

    Long Polling Method (default)

    This way, you send HTTPS requests to Telegram bot API, and you’d get updates as response in a JSON-formatted object. So, the following work can be done to get new updates (API, why using offset):

    $botToken = "<token>";
    
    $updates = json_decode(file_get_contents("https://api.telegram.org/bot{$botToken}/getUpdates?offset={$lastUpdateId->get()}"), true);
    
    // Split updates from each other in $updates
    // It is considered that one sample update is stored in $update
    
    // See the section below
    parseUpdate($update);
    

    WebHook Method (preferred)

    Requiring support for HTTPS POST method from your server, the best way of getting updates at-the-moment.

    Initially, you must enable WebHooks for your bot, using the following request (more details):

    https://api.telegram.org/bot<token>/setWebhook?url=<file>
    

    Replace <token> with you bot token, and <file> with the address of your file which is going to accept new requests. Again, it must be HTTPS.

    OK, the last step is creating your file at the specified URL:

    // The update is sent
    $update = $_POST;
    
    // See the section below
    parseUpdate($update);
    

    From now, all requests and updates your bot will be directly sent to the file.

    Implementation of parseUpdate()

    Its implementation is totally up to you. However, to show how to use the class above in the implementation, this is a sample and short implementation for it:

    function parseUpdate($update)
    {
        // Validate $update, first
        // Actually, you should have a validation class for it
    
        // Here, we suppose that: $update["update_id"] !== null
        if ($lastUpdateId->isNewRequest($update["update_id"])) {
            $lastUpdateId->set($update["update_id"]);
            // New request, go on
        } else {
            // Old request (or possible file error)
            // You may throw exceptions here
        }
    }
    

    Enjoy!

    Edit: Thanks to @Amir for suggesting editions made this answer more complete and useful.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search