DEV Community

Cover image for Deploy a Telegram bot for free with Claude Code
Philipp Shayzhanov
Philipp Shayzhanov

Posted on Originally published at vbtnl.com

Deploy a Telegram bot for free with Claude Code

You want a Telegram bot that works all the time, not only when your laptop is on. For that you need three things:

  • a bot token from BotFather,
  • a public HTTPS address, so Telegram can send messages to your bot,
  • a server that keeps the bot running.

The token is easy. The other two usually mean a VPS: you rent a server, set up a web server, get a certificate, and make sure the bot restarts when it crashes.

This guide skips all of that. You tell Claude Code what bot you want. It builds the bot on vbtnl and gives you a live address. The full code is below, so you can see what runs.

  you                Claude Code               vbtnl                 Telegram
   |                      |                      |                      |
   |  "build a bot"       |                      |                      |
   |--------------------->|  write, run, publish |                      |
   |                      |--------------------->|  setWebhook (HTTPS)  |
   |                      |                      |--------------------->|
   |                      |                      |                      |
   |  a message to the bot                                              |
   |-------------------------------------------------------------------->|
   |                      |                      |   POST /webhook      |
   |                      |                      |<---------------------|
   |                      |                      |   sendMessage        |
   |                      |                      |--------------------->|
   |  the bot replies                                                   |
   |<--------------------------------------------------------------------|
Enter fullscreen mode Exit fullscreen mode

What you need

  • Claude Code. Codex works too, the steps are the same.
  • A Telegram account.
  • A vbtnl account. The free plan is enough for one bot, and you don't need a card.

Step 1. Get a token from BotFather

In Telegram, open @BotFather and send /newbot. Choose a name, then a username that ends with bot. BotFather sends you a token. It looks like 123456789:AAH....

Don't share the token. Anyone who has it can control your bot.

Step 2. Connect vbtnl to Claude Code

vbtnl is an MCP server. You add it to Claude Code once:

claude mcp add --transport http vbtnl https://api.vbtnl.com/mcp
Enter fullscreen mode Exit fullscreen mode

Then type /mcp in Claude Code, pick vbtnl and log in. Now Claude Code can create projects on vbtnl, write files there, run commands and publish.

Step 3. Ask for the bot

Here is the prompt:

Build a Telegram bot on vbtnl. It answers /start with a greeting and repeats any other
message back. Use a webhook, not polling. I will give you the bot token as a secret.
Enter fullscreen mode Exit fullscreen mode

Claude Code will ask for the token. Paste it in the chat. It saves the token as a secret, so the token never ends up in a file.

Then the agent does the work, step by step:

  1. create_project creates a project with two addresses: a draft for testing and production for real use.
  2. set_secrets saves the token and a random WEBHOOK_SECRET.
  3. write_files writes the code.
  4. exec sends a test message to the draft to check that it answers.
  5. publish puts the bot into production.

The code

The agent writes the code for you, so your bot will look a bit different. But it will be close to this. There are three files.

vbtnl.json tells vbtnl how to start the app:

{
  "stack": "python",
  "start": "uvicorn main:app --host 0.0.0.0 --port $PORT"
}
Enter fullscreen mode Exit fullscreen mode

requirements.txt:

fastapi
uvicorn
httpx
Enter fullscreen mode Exit fullscreen mode

main.py:

import os
from contextlib import asynccontextmanager

import httpx
from fastapi import FastAPI, Header, HTTPException, Request

TOKEN = os.environ["TELEGRAM_BOT_TOKEN"]
SECRET = os.environ["WEBHOOK_SECRET"]
API = f"https://api.telegram.org/bot{TOKEN}"


@asynccontextmanager
async def lifespan(app: FastAPI):
    # Only production connects to Telegram. The draft is tested with curl.
    if os.environ.get("VBTNL_ENV") == "prod":
        async with httpx.AsyncClient() as client:
            await client.post(f"{API}/setWebhook", json={
                "url": f"{os.environ['VBTNL_URL']}/webhook",
                "secret_token": SECRET,
            })
    yield


app = FastAPI(lifespan=lifespan)


@app.post("/webhook")
async def webhook(request: Request, x_telegram_bot_api_secret_token: str = Header(default="")):
    if x_telegram_bot_api_secret_token != SECRET:
        raise HTTPException(status_code=403)
    update = await request.json()
    message = update.get("message") or {}
    chat_id = (message.get("chat") or {}).get("id")
    if chat_id is None:
        return {"ok": True}
    text = message.get("text", "")
    if text == "/start":
        reply = "Hi! Send me anything and I will repeat it."
    else:
        reply = f"You said: {text}"
    async with httpx.AsyncClient() as client:
        await client.post(f"{API}/sendMessage", json={"chat_id": chat_id, "text": reply})
    return {"ok": True}
Enter fullscreen mode Exit fullscreen mode

You don't set PORT, VBTNL_ENV or VBTNL_URL yourself, vbtnl does it. VBTNL_URL is the public address of the bot. When the bot starts, it sends this address to Telegram, so you never copy a URL by hand.

Webhook or polling?

A bot can get messages in two ways:

  • Polling. The bot asks Telegram again and again: "Any new messages?"
  • Webhook. Telegram sends every new message to the bot's address.

Polling is fine on your laptop. On a server, a webhook is better. The bot does nothing until a message comes, it answers faster, and it is just a normal web app. Telegram sends webhooks only to HTTPS addresses. Every vbtnl address already has HTTPS, so there is no certificate to set up.

Watch out. One bot token can have only one webhook. If both the draft and production register it, the one that started last gets the messages and the other one is silent. That is why the code registers the webhook only in production.

The secret token

The webhook address is public. Anyone who finds it can send fake messages to your bot.

Telegram has a simple fix. When you call setWebhook, you also send a secret_token. Then Telegram puts this value in the X-Telegram-Bot-Api-Secret-Token header of every request. The code checks the header and answers 403 if it is wrong.

Keep this secret where you keep the bot token: in the project secrets, not in the code.

Step 4. Test, then publish

The draft doesn't get real messages from Telegram. So ask the agent to test it:

Send a fake /start update to the draft and show me the response.
Enter fullscreen mode Exit fullscreen mode

It sends a fake message with curl and shows you the answer and the logs. If everything looks good, write:

Ship it.
Enter fullscreen mode Exit fullscreen mode

The agent publishes the bot. Production starts, connects to Telegram, and the bot is live. Open it in Telegram and send /start.

Make the bot write first

Sometimes you want the bot to send something on its own. For example:

Every day at 9:00 UTC send "Good morning" to my chat. My chat id is 123456789.
Enter fullscreen mode Exit fullscreen mode

The agent adds a small script and a schedule to vbtnl.json:

{
  "stack": "python",
  "start": "uvicorn main:app --host 0.0.0.0 --port $PORT",
  "cron": [{ "schedule": "0 9 * * *", "run": "python daily.py" }]
}
Enter fullscreen mode Exit fullscreen mode

Schedules use the normal cron format and UTC time. A project can have up to 10 of them. Don't know your chat id? Send any message to the bot and ask the agent to find it in the logs.

If something goes wrong

  • The bot doesn't answer after publishing. Ask the agent to check the production logs and the webhook. Most of the time the token is wrong.
  • It worked, but stopped after a change. Ask the agent to roll back. Every publish is saved as a version, and going back takes one step.
  • You want to save users or messages. Ask for a database. The agent adds Postgres, and the bot gets its address in DATABASE_URL. Don't save data to files in production: files are lost when the app restarts.

Is it really free and online 24/7?

For one bot, yes. The free plan has one project, and you don't need a card. Production doesn't sleep when nobody writes to the bot.

This is important for bots. Many free hosts stop your app after a few minutes without traffic. With a webhook that breaks the bot: Telegram sends a message, and nothing is there to answer. On vbtnl only the draft sleeps, and it wakes up when the agent works with it.

On the free plan the bot gets 0.5 vCPU, 1.25 GB of RAM, a 1 GB Postgres database and an address on vbtnl.site.

What it costs

One bot is free. Paid plans start at $19 a month. You get more projects, more CPU and memory, and your own domain. See pricing.

Questions

Do I need a VPS for a Telegram bot?

No. With a VPS you install Python, a web server, a certificate and a process manager yourself. Here vbtnl runs the app, gives it HTTPS and restarts it when needed. The agent does the setup.

Can I use Codex instead of Claude Code?

Yes. Add vbtnl with codex mcp add vbtnl --url https://api.vbtnl.com/mcp, then run codex mcp login vbtnl. Use the same prompt.

Can I write the bot in Node.js?

Yes. vbtnl runs Python 3.12 and Node.js 22. Say which one you want in the prompt.

Do I need to know Python?

No. The agent writes the code and fixes it. The code is here so you can see what runs, not because you need to type it.

I already have a bot. Can I move it here?

Yes. Ask the agent to put your files into a project and publish them. Two rules: the app must listen on $PORT, and it must read the token from an environment variable.

More answers are in the FAQ.

Build your bot with one message. Connect vbtnl to Claude Code or Codex, describe the bot, and get a live address.

Originally published on the vbtnl blog.

Top comments (6)

Collapse
 
markowebdev profile image
markoweb.dev •

Great one! Thanks!

Have you built something interesting already and what your bot can actually do in simple words?

Collapse
 
kinzarra profile image
Philipp Shayzhanov •

Yes, quite a few bots by now. My favorite one I made for an influencer marketing agency. It helps them work with influencers: it takes over the boring routine, so the team spends less time on manual work and more time on the actual campaigns.

The idea is the same as in this post. I describe what I want in plain words, Claude Code writes the bot, and vbtnl keeps it running 24/7.

What kind of bot are you thinking about?

Collapse
 
kinzarra profile image
Philipp Shayzhanov •

Thanks, glad it helped! If you try it, tell me how it went.

Collapse
 
markowebdev profile image
markoweb.dev •

Sure,thank You!

Collapse
 
kinzarra profile image
Philipp Shayzhanov •

And the most fantastic is that i can deploy everything in just 3 mins))

Collapse
 
kinzarra profile image
Philipp Shayzhanov •

the-daily-ten.vbtnl.site/ like this) it is really simple but I did not try to do smth special for 3 mins)