Home › Guides › How to build a Telegram odds bot

How to build a Telegram odds bot

Updated September 25, 2026 · facts checked against the dated sources listed below

An odds bot needs three pieces: a token from Telegram's BotFather, a loop that asks Telegram for new messages, and a data source to answer from. This guide builds one in 65 lines of standard-library Python that replies to /odds fed december with matching Polymarket markets from this site's free JSON API, credit included.

Step 1: create the bot and protect the token

In Telegram, open a chat with @BotFather and send /newbot. It asks for a display name and a username, then replies with an authentication token. Telegram's documentation warns that anyone who has the token can control your bot, so keep it out of your code and out of version control: the script reads it from an environment variable named TELEGRAM_BOT_TOKEN. If the token leaks, BotFather's /token command generates a new one.

Step 2: choose long polling or a webhook

Telegram offers two ways to receive messages, and a bot can use only one at a time. With long polling, your script calls getUpdates with a timeout and Telegram holds the request open until something arrives; each call passes an offset one higher than the last update_id you handled, which tells Telegram the earlier updates are done. With a webhook, set with setWebhook, Telegram sends each update to your HTTPS address on port 443, 80, 88 or 8443. Either way, updates wait on Telegram's servers for up to 24 hours.

Polling works from a laptop or any machine without a public address, so it suits a small bot; a webhook needs a public HTTPS endpoint but spares you an open connection. The script below polls.

Step 3: run the bot

Save the script as odds_bot.py, set the token in your shell and start it, then message your bot /odds fed december or /odds recession. It uses only Python's standard library: urllib.request for HTTP, urllib.parse to encode the parameters and json to read the replies.

import json
import os
import time
import urllib.parse
import urllib.request

TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
TELEGRAM = "https://api.telegram.org/bot" + TOKEN + "/"
ODDS_INDEX = "https://polymarkettrader.com/api/v1/odds/index.json"
HEADERS = {"User-Agent": "my-odds-bot/1.0"}
CACHE_SECONDS = 1800
cache = {"data": None, "time": 0.0}


def call(url, params=None, timeout=30):
    if params:
        url += "?" + urllib.parse.urlencode(params)
    request = urllib.request.Request(url, headers=HEADERS)
    with urllib.request.urlopen(request, timeout=timeout) as response:
        return json.load(response)


def odds_index():
    if cache["data"] is None or time.time() - cache["time"] > CACHE_SECONDS:
        cache["data"] = call(ODDS_INDEX)
        cache["time"] = time.time()
    return cache["data"]


def answer(query):
    words = query.lower().split()
    if not words:
        return "Send /odds and a few words, for example: /odds fed december"
    data = odds_index()
    hits = [m for m in data["markets"] if all(w in m["title"].lower() for w in words)]
    if not hits:
        return "No tracked market matches: " + " ".join(words)
    lines = [f'{m["title"]}\n{m["leader"]}: {m["probability"]:.1%}\n{m["url"]}' for m in hits[:3]]
    built = data["updated"][:16].replace("T", " ")
    lines.append(f'{data["attribution"]["text"]} {data["attribution"]["url"]} ({data["license"]}), updated {built} UTC')
    return "\n\n".join(lines)


def main():
    offset = None
    while True:
        try:
            params = {"timeout": 50}
            if offset is not None:
                params["offset"] = offset
            updates = call(TELEGRAM + "getUpdates", params, timeout=60)
            for update in updates["result"]:
                offset = update["update_id"] + 1
                message = update.get("message") or {}
                command, _, query = message.get("text", "").partition(" ")
                if command.split("@")[0] in ("/odds", "/start"):
                    reply = answer(query)
                    call(TELEGRAM + "sendMessage", {"chat_id": message["chat"]["id"], "text": reply})
        except Exception as error:
            print("error:", error)
            time.sleep(5)


if __name__ == "__main__":
    main()
export TELEGRAM_BOT_TOKEN="paste-the-token-from-BotFather-here"
python3 odds_bot.py

How the bot reads the odds

answer() searches the titles in /api/v1/odds/index.json for every word you typed and returns up to three matches, each with its leading outcome, probability and a link to the market's page on this site. It reads only fields the index publishes: title, leader, probability and url for each market, plus updated, license and the attribution text and url for the credit line. Matching is deliberately simple: every word must appear in the title, so /odds bitcoin september narrows the list faster than /odds bitcoin. Three matches stay far below Telegram's limit of 4,096 characters per message.

odds_index() keeps the file in memory for 30 minutes. The data changes only about twice a day, so downloading it for every message would add load without adding freshness. The script also sends its own User-Agent, because our CDN rejects Python's default one.

See also: How to use the free odds API

Credit, limits and next steps

Every reply ends with the credit line, link and license name from the file and the time the data was built; CC BY 4.0 also asks for a link to the license itself, which you can put in the bot's description or its /start reply. Telegram's FAQ asks bots to avoid sending more than one message per second in a single chat and says a bot cannot send more than 20 messages per minute to a group, so answer on demand or batch your alerts. A command can also arrive with the bot's username attached, as /odds@YourBotName, the form of the Bot API's own example /start@jobs_bot; the script drops the part after the @ so both forms work.

To turn it into an alert bot, save each market's probability on every refresh and message a chat when one moves by more than a threshold you pick, such as 5 points. Before sharing it widely, add logging, run it under a process manager and never paste the token into a chat or a repository.

See also: How to build a prediction market watchlist · Free odds API and endpoints

Sources

Frequently asked questions

Do I need a Telegram bot library?

No. The Bot API takes plain HTTPS requests and returns JSON, so the standard library is enough for a small bot; a library can add conveniences as it grows.

Where should I keep the bot token?

In an environment variable or a secrets manager, never in the code. Anyone with the token controls the bot, and BotFather can generate a new one if it leaks.

Why does the odds request fail with a 403?

At the time of writing, our CDN rejects requests that identify as Python-urllib, the default of Python's standard library. Send your own User-Agent header, as the script does.

How fresh are the bot's odds?

The API is rebuilt about twice a day and the bot caches it for 30 minutes, so a reply can be several hours old; each reply shows when the data was built.

Polymarket View is independent and not affiliated with Polymarket. Educational information, not financial advice. All guides · How market types work · Glossary · Polymarket odds today