How to Build a Prediction Market Telegram Bot With an API

The Short Answer
Create a bot with BotFather, get its token, then wire two HTTP calls together: subscribe to Predictefy's orderbook channel for the markets you care about, and POST to Telegram's sendMessage when a threshold is crossed. The whole thing is under a hundred lines. The free API key covers 15+ venues, so one bot watches every venue rather than one bot per venue.
A Telegram bot is the cheapest useful interface you can put on market data. No frontend, no hosting a UI, no login. You send a message and it appears on someone's phone.
The build is genuinely small. What takes the time is the parts nobody mentions: Telegram's rate limits, how to stop the bot shouting, and what happens when the process restarts.
Key Takeaways
- Two moving parts: a Predictefy subscription for prices and Telegram's
sendMessagefor delivery. - Telegram limits you to roughly one message per second per chat, and about 30 per second overall. Batch or you will be throttled.
- Store the last state per rule so the bot fires on a crossing, not on every tick that stays past the line.
- Use
getExecutionPricerather than a mid price, so an alert reflects a trade someone could actually make. - One API key covers 15+ venues, so adding a venue is a string change rather than another integration.
Creating the Bot
Message @BotFather on Telegram, send /newbot, pick a name and a username. You get a token that looks like 123456789:AAH.... That token is a credential. It belongs in an environment variable, not in your repository.
Next you need a chat id, because a bot cannot message someone who has not spoken to it first. Send your bot a message, then read it back:
curl "https://api.telegram.org/bot$TOKEN/getUpdates"
Returns recent messages sent to your bot. The message.chat.id in the response is the id you send to. For a group, add the bot to the group first and send a message there; group ids are negative numbers, which is normal and not an error.
Sending a Message
async function send(text) {
await fetch(`https://api.telegram.org/bot${process.env.TG_TOKEN}/sendMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: process.env.TG_CHAT_ID,
text,
parse_mode: 'HTML',
disable_web_page_preview: true
})
});
}
One POST and the message is delivered. parse_mode: 'HTML' lets you bold a price without wrestling with Markdown escaping, and disabling the link preview stops a market URL expanding into a large card that buries the number you sent.
Wiring In Prices
Now the other half. Subscribe once and let the venue push updates to you.
import Predictefy from '@predictefy/sdk';
const client = new Predictefy({ apiKey: process.env.PREDICTEFY_API_KEY });
const lastSide = new Map();
const watch = (venue, marketId, label, threshold) =>
client.watchOrderBook({ venue, marketId }, ({ data }) => {
const ask = data.asks[0]?.price;
if (ask === undefined) return;
const key = `${venue}:${marketId}`;
const above = ask >= threshold;
const before = lastSide.get(key);
lastSide.set(key, above);
if (before === undefined || before === above) return;
send(`<b>${label}</b>\n${venue} ask ${ask} crossed ${threshold}`);
});
Watches one market and sends only when the ask crosses the threshold, not on every tick that remains past it. The before === undefined guard means the first tick after a restart records state silently, so restarting the process does not fire every rule at once.
Adding a second venue is one more call with a different venue string. Nothing else changes, because the book shape is the same across all 15+ venues.
Telegram's Rate Limits
This is where working bots become annoying bots. Telegram allows roughly one message per second to a single chat and around 30 per second overall. Exceed it and you get a 429 with a retry_after, and messages start disappearing.
A volatile market can trip forty rules in a few seconds. The fix is a queue with a floor on spacing, and batching anything that arrives together.
const queue = [];
let draining = false;
function enqueue(text) {
queue.push(text);
if (!draining) drain();
}
async function drain() {
draining = true;
while (queue.length) {
// One message carrying five lines beats five messages.
const batch = queue.splice(0, 10).join('\n');
await send(batch);
await new Promise((r) => setTimeout(r, 1100));
}
draining = false;
}
Collects alerts and sends at most one message every 1.1 seconds, combining up to ten into a single message. A burst of forty alerts becomes four messages over four seconds instead of forty rejected requests.
Taking Commands
A bot that only pushes is a notifier. Accepting commands turns it into something people use. The simplest approach is long polling: ask Telegram for new messages, act on them, repeat.
let offset = 0;
async function poll() {
const res = await fetch(
`https://api.telegram.org/bot${process.env.TG_TOKEN}/getUpdates?timeout=30&offset=${offset}`
).then((r) => r.json());
for (const update of res.result ?? []) {
offset = update.update_id + 1;
const text = update.message?.text ?? '';
if (text.startsWith('/price ')) {
const book = await client.router.fetchMarkets({ query: text.slice(7) });
send(formatResults(book));
}
}
poll();
}
Holds a request open for 30 seconds waiting for messages, which costs far less than polling in a tight loop. Advancing offset past each update is what stops you processing the same message forever. The /price handler searches all 15+ venues at once through the router.
Why the Venue Layer Matters Here
The Telegram half of this bot is the same whatever data you put behind it. The half that decides whether the project survives is the market data.
Written per venue, you maintain a WebSocket client for Kalshi, another for Polymarket with its own identifier scheme, another for SX Bet on Centrifugo, and each one breaks independently. Through Predictefy it is one connection, one book shape and one reconnect strategy across 15+ venues, so the bot above gains a venue by changing a string. The API key is free to start with a monthly credit allowance, which comfortably covers a personal bot.
Frequently Asked Questions
How do I build a prediction market Telegram bot?
Create a bot with BotFather for a token, subscribe to market data, and POST to Telegram's sendMessage when a condition is met. Predictefy's free API key streams 15+ venues through one connection, so the bot covers every venue without a separate integration for each.
Why is my Telegram bot getting 429 errors?
You are exceeding roughly one message per second per chat, or about 30 per second overall. A volatile market can trip many rules at once. Queue outgoing messages, enforce a minimum gap of just over a second, and batch several alerts into one message.
Why can my bot not message me?
A Telegram bot cannot start a conversation. Message it first, then call getUpdates and read message.chat.id from the response. For groups, add the bot to the group and send a message there; group ids are negative, which is expected rather than an error.
Should the bot poll or stream for prices?
Stream. Polling reacts on your interval at best, so a market that moves and settles between checks never triggers. Predictefy's streaming API pushes book updates as they happen and bills per connection-minute rather than per request, which suits continuous watching.
Can one bot watch several venues at once?
Yes, and that is the main reason to use an aggregation layer. Predictefy exposes 15+ venues through one connection with one book shape, so adding a venue means changing a venue string rather than writing another WebSocket client with its own quirks.
Conclusion
The bot itself is two HTTP calls. What separates one people keep and one they mute is restraint: fire on crossings rather than states, batch bursts into single messages, and respect the rate limit before Telegram enforces it for you.
Build the alerting logic first and the Telegram wiring last. The delivery is the easy half.
One housekeeping note: this is information, not financial advice. Endpoints, limits and credit costs change, so confirm anything that matters against the current documentation.