1. Docs
  2. Integrations
  3. Telegram

Build a Telegram astrology bot with RoxyAPI

Ship a working /horoscope, /kundli, or /tarot bot on Telegram in under 20 minutes. One Bot API token from BotFather, one Roxy API key, two screens of code.

Telegram is the easiest messaging platform to ship a bot on. The official Bot API is a plain JSON-over-HTTPS surface, BotFather hands you a token in three messages, and your handler can run anywhere that can speak HTTPS. RoxyAPI provides the astrology, tarot, and numerology answers your bot replies with: 130+ endpoints across 10 domains behind one key, plus a remote MCP server per domain when you want an LLM to pick the right call on its own.

TL;DR

  • You will ship a Telegram bot that replies to /horoscope <sign>, /tarot, and /lifepath <YYYY-MM-DD> with live RoxyAPI data
  • You need a BotFather token (free) and a RoxyAPI key. Plans start at $39 a month for 25K requests; a free test key is available on request via contact
  • Working code in three languages, ready to deploy. About 15 minutes start to finish

What you can build on Telegram

  • A daily horoscope DM that fires from a cron at 8 AM for every subscriber
  • A /kundli command that asks for birth date, time, and place, then replies with a Vedic chart
  • A /tarot command that draws a daily card and sends the card image as sendPhoto
  • A /numerology flow that returns Life Path, Expression, and Soul Urge from a name and date
  • A group bot that drops the daily moon phase or hexagram into a chat at sunset
  • A multi-language support bot that calls Roxy with ?lang=hi or ?lang=tr for non-English users
  • An AI agent bot where the LLM picks between horoscope, kundli, and tarot endpoints based on the question

What you need, 30 seconds

  1. A Telegram account and the BotFather chat open. Free.
  2. A RoxyAPI key. Plans start at $39 a month on the pricing page; a free test key for evaluation is available on request via contact.
  3. A place to run the handler. Local laptop with ngrok for testing, or any HTTPS host (Vercel, Fly.io, Railway, Render, your own server) for production.
  4. About 15 minutes.

Run the quickstart curl in a terminal first. A 200 response confirms the Roxy key is good before you wire it into any handler.

Step 1, register your bot and pick a transport

Open a chat with @BotFather, send /newbot, pick a name and a username ending in bot. BotFather replies with an HTTP token like 12345:ABC.... Save it. That token authenticates every call your handler makes back to Telegram.

Telegram offers two transports. Pick based on whether you have a public HTTPS URL.

Your handler loops, calling getUpdates, processes each message, replies. No webhook, no HTTPS host, no signing. Run it on your laptop, run it in a Docker container, run it during a demo.

# One-shot poll. Starts the conversation feedback loop.
curl "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/getUpdates"

Use long polling for prototyping and bots with low message volume. Switch to webhooks once you deploy.

Step 2, ship the /horoscope command

The handler watches for /horoscope <sign>, calls Roxy, and replies. The example below runs over the webhook transport from Step 1, but the body of each handler also works inside a long-polling loop without changes.

Verify the Roxy call is correct before wiring anything to Telegram.

curl "https://roxyapi.com/api/v2/astrology/horoscope/aries/daily" \
  -H "X-API-Key: $ROXY_API_KEY"

You should get back JSON with sign, date, overview, love, career, luckyNumber, moonSign, moonPhase, and energyRating. Pick the fields you want in the bot reply.

Send /horoscope aries to your bot. You should get back the daily reading within a second.

Bonus, a /tarot command that sends the card image

The tarot/daily response carries card.imageUrl, a public CDN URL. The Telegram sendPhoto method accepts a remote URL directly, so you can return the card image with no extra hosting.

Drop this block inside the app.post('/webhook', ...) handler from above; it reuses the same roxy, msg, and TG variables.

const { data } = await roxy.tarot.getDailyCard({ body: { seed: String(msg.from.id) } });
await fetch(`${TG}/sendPhoto`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    chat_id: msg.chat.id,
    photo: data.card.imageUrl,
    caption: `${data.card.name}${data.card.reversed ? ' (reversed)' : ''}\n\n${data.dailyMessage}`,
  }),
});

Seeding by msg.from.id makes the daily card deterministic per user per day. Same user calls /tarot ten times before midnight, gets the same card every time. Works the same way in Python via roxy.tarot.get_daily_card(seed=str(msg['from']['id'])).

Step 3, scale to the full surface

Adding a new command is the same shape as /horoscope. Pick the endpoint, build the parameters, format the reply.

Any chart, horoscope, panchang, dasha, dosha, navamsa, KP, synastry, or compatibility endpoint needs latitude, longitude, and timezone. Always call roxy.location.searchCities (TS) or roxy.location.search_cities (Py) first and feed the result through. The server resolves IANA strings like "Asia/Kolkata" to the DST-correct offset for the chart date, so January births in New York pick EST and July births pick EDT automatically.

Add an MCP-powered AI agent (optional)

Hardcoded /horoscope and /tarot commands are fine for a focused bot. For a free-text bot ("what does my chart say about my career?"), point an LLM at the Roxy MCP server and let it pick the endpoint.

The remote MCP server runs at https://roxyapi.com/mcp/{domain} over Streamable HTTP. No stdio, no Docker, no local setup. Point Claude Code, Cursor, OpenAI Agents SDK, or any other MCP-aware client at the URL with your X-API-Key header. The agent inspects tools/list, picks the right tool, builds parameters, and calls Roxy. From inside your Telegram handler, the LLM owns the routing logic; you only forward msg.text to the agent and reply with the result.

tools/list is free. Every tools/call bills the same as the equivalent REST call. See /docs/mcp for the full setup.

Frequently asked questions

Is the test API key OK for production?

No. The shared test key on API reference is rate-limited and rotates. For your bot, mint a real key on the pricing page. The Starter plan ($39 a month) covers 25K requests, enough to run a small bot end to end. If you need more headroom for evaluation before paying, request a free test key via contact.

How do I keep the bot from burning quota in group chats?

Long polling and webhooks both deliver every message in groups your bot is added to. Filter on msg.text.startsWith('/') so only commands trigger Roxy calls. Cache daily content per user with a short-lived KV (Redis, SQLite) so the same user calling /horoscope aries ten times in a minute pays for one call.

Can the bot reply in Hindi, Spanish, or Turkish?

Yes. Most Roxy domains accept a lang query parameter (en, tr, de, es, fr, hi, pt, ru). In the SDK, pass query: { lang: 'hi' } (TS) or lang='hi' (Py). Detect the user language from msg.from.language_code (Telegram passes IETF tags) and forward it.

What happens when a user sends a malformed birth date?

Roxy returns a 400 with code: validation_error. Catch it (TS: if (error), Python: except RoxyAPIError as e), reply with a friendly message, and log the raw error for debugging. Never let the 400 bubble up as a generic Telegram crash.

Do I need to verify webhook payloads?

Telegram does not sign webhook bodies the way Slack and WhatsApp do. The standard defense is a secret_token you pass to setWebhook and check on every incoming request via the X-Telegram-Bot-Api-Secret-Token header. Add it once you go to production.

Gotchas

  • Backend-only key. The Roxy key lives in your handler, never in a client message. If you proxy something to Telegram users, never echo process.env.ROXY_API_KEY.
  • Telegram chat IDs are integers, not strings. Use them as numbers. JSON serialization handles both, but typed code in TS or Pydantic in Python should match.
  • Webhook URL must be HTTPS. Self-signed certs work only with the certificate form-data parameter on setWebhook. Use ngrok for local dev, a real cert in production.
  • text is missing on photo, sticker, or location messages. Always guard if (!msg?.text) before parsing commands.
  • Group bots see every message by default. BotFather, /setprivacy to enable Privacy Mode so the bot only sees commands and replies, unless you actually want full feeds.
  • Send formatting matters. sendMessage with parse_mode: 'HTML' or 'MarkdownV2' lets you bold the sign and italicize the advice. Without parse_mode everything is plain text.
  • Telegram rate limits are 30 messages per second to different chats and 1 per second to the same chat. A bulk send to 1000 users needs throttling.
  • MCP tools/call is billable, tools/list is free. When debugging an agent, the discovery call does not count, the actual answer does.

What to build next