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 |
|<--------------------------------------------------------------------|
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
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.
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:
-
create_projectcreates a project with two addresses: a draft for testing and production for real use. -
set_secretssaves the token and a randomWEBHOOK_SECRET. -
write_fileswrites the code. -
execsends a test message to the draft to check that it answers. -
publishputs 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"
}
requirements.txt:
fastapi
uvicorn
httpx
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}
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.
It sends a fake message with curl and shows you the answer and the logs. If everything looks good, write:
Ship it.
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.
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" }]
}
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)
Great one! Thanks!
Have you built something interesting already and what your bot can actually do in simple words?
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?
Thanks, glad it helped! If you try it, tell me how it went.
Sure,thank You!
And the most fantastic is that i can deploy everything in just 3 mins))

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