Telegram bot payments let you sell digital goods, subscriptions, or services directly inside a chat, without redirecting users to a separate checkout page. If you’re building a bot that needs to charge customers, telegram bot payments give you a native invoice UI, built-in provider integration, and a webhook-driven flow that fits naturally into an existing DevOps or automation stack. This guide walks through how the system works, how to set it up correctly, and how to run it reliably in production.
What Are Telegram Bot Payments and How They Work
Telegram bot payments are a built-in feature of the Telegram Bot API that lets a bot send an invoice message to a user, collect shipping and payment details inside the Telegram client, and receive a confirmation once the charge succeeds. Telegram itself never touches the money — it acts as a UI and messaging layer on top of a real payment provider (Stripe, for example, is the most common choice for most regions).
The flow has three moving parts:
Because Telegram sits in the middle, telegram bot payments don’t require you to build a custom checkout UI. The invoice, currency formatting, and payment method entry are all handled by the Telegram client itself, which reduces the amount of frontend work significantly compared to a typical e-commerce integration.
The Three Payment Events You Must Handle
Every telegram bot payments integration revolves around three API objects your bot needs to respond to:
sendInvoice — the message your bot sends to initiate a purchase.pre_checkout_query — an event Telegram sends right before the charge is finalized, giving your bot a last chance to confirm the order is still valid (stock available, price still correct, etc.).successful_payment — the confirmation message that arrives once the charge has actually gone through.If your bot doesn’t answer the pre_checkout_query within a short timeout, Telegram cancels the transaction automatically. This is a common source of “payment just hangs” bugs, and it’s usually caused by a slow database lookup or an unhandled exception in the pre-checkout handler.
Setting Up Telegram Bot Payments With BotFather
Before you write any code, the provider connection has to be configured through BotFather, Telegram’s own bot-management bot. This step is easy to skip past and comes up constantly in support threads, so it’s worth doing carefully.
1. Open a chat with @BotFather and select the bot you want to enable payments on.
2. Choose Payments from the bot’s settings menu.
3. Pick a payment provider from the list Telegram offers for your bot’s region.
4. Connect your provider account and copy the provider token BotFather gives you — this is what your code uses to authorize invoices.
Registering a Payment Provider Token
The provider token is a secret and should be treated exactly like an API key or database password — never commit it to source control, and never log it. If you’re already using Docker Compose Secrets to manage other credentials in your stack, the provider token belongs in the same place rather than in a plaintext environment file checked into git.
A minimal docker-compose.yml snippet for a bot service that reads the token from a secret file looks like this:
services:
telegram-bot:
build: .
environment:
- PROVIDER_TOKEN_FILE=/run/secrets/telegram_provider_token
- TELEGRAM_BOT_TOKEN_FILE=/run/secrets/telegram_bot_token
secrets:
- telegram_provider_token
- telegram_bot_token
secrets:
telegram_provider_token:
file: ./secrets/telegram_provider_token.txt
telegram_bot_token:
file: ./secrets/telegram_bot_token.txtTesting With Stripe’s Test Mode
If you connect Stripe as your provider, BotFather also gives you a separate test-mode provider token. Use it during development so you can run through the full telegram bot payments flow — invoice, pre-checkout, successful payment — with Stripe’s documented test card numbers instead of a real card. Switching to the live token should be a deployment-time configuration change, not a code change, so you never risk accidentally testing against real money.
Implementing the Payment Flow in Your Bot
Once the provider token is configured, the actual code for telegram bot payments is fairly small. Here’s a minimal example using Python and the python-telegram-bot library that sends an invoice and handles both required callbacks:
pip install python-telegram-bot==21.*from telegram import LabeledPrice, Update
from telegram.ext import Application, CommandHandler, PreCheckoutQueryHandler, MessageHandler, filters
PROVIDER_TOKEN = "YOUR_PROVIDER_TOKEN"
async def send_invoice(update: Update, context):
chat_id = update.effective_chat.id
await context.bot.send_invoice(
chat_id=chat_id,
title="Pro Plan - 1 Month",
description="Unlocks premium bot features for 30 days.",
payload="pro-plan-1m",
provider_token=PROVIDER_TOKEN,
currency="USD",
prices=[LabeledPrice("Pro Plan", 999)], # amount in cents
)
async def precheckout_callback(update: Update, context):
query = update.pre_checkout_query
if query.invoice_payload != "pro-plan-1m":
await query.answer(ok=False, error_message="Something went wrong.")
else:
await query.answer(ok=True)
async def successful_payment_callback(update: Update, context):
payment = update.message.successful_payment
# Grant access, update your database, send a confirmation.
await update.message.reply_text("Payment received - your plan is now active.")
app = Application.builder().token("YOUR_BOT_TOKEN").build()
app.add_handler(CommandHandler("buy", send_invoice))
app.add_handler(PreCheckoutQueryHandler(precheckout_callback))
app.add_handler(MessageHandler(filters.SUCCESSFUL_PAYMENT, successful_payment_callback))
app.run_polling()Handling send_invoice, precheckout_query, and successful_payment
Notice that the pre-checkout handler answers within the request itself — no external API call, no slow database round-trip. That’s deliberate: Telegram enforces a strict timeout on pre_checkout_query responses, and if your handler does anything expensive (like calling out to an inventory service), you should do it asynchronously and fail safe rather than block the callback.
The successful_payment_callback is where you’ll typically write to your own database, trigger fulfillment, or send a receipt. This is also the natural point to fire an event into a broader automation pipeline if you’re running one — for example, notifying an n8n Self Hosted workflow that a new order needs processing.
Automating Order Fulfillment With n8n
Once telegram bot payments are working, most of the ongoing engineering work isn’t the payment code itself — it’s what happens after a payment succeeds: provisioning access, updating a CRM, sending a receipt email, or logging the transaction for accounting. Wiring the bot’s successful_payment handler to call a webhook is usually simpler than building that logic into the bot itself.
A typical pattern:
successful_payment_callback posts the payment payload to an n8n webhook.Keeping fulfillment logic outside the bot process makes it easier to change business logic without redeploying the bot, and it keeps the bot codebase focused on the messaging and payment flow. If you’re deploying both the bot and an automation engine on the same infrastructure, a mid-tier VPS from a provider like DigitalOcean is usually enough to run both services comfortably for low-to-moderate transaction volume.
Securing Telegram Bot Payments in Production
Payment code deserves more scrutiny than an average feature, and telegram bot payments are no exception. A few practices matter more here than in most other parts of a bot:
pre_checkout_query, not just at invoice-creation time — prices or stock can change between the two events.payment_charge_id and your own internal order ID, but avoid logging full card or personal data — Telegram and the provider handle that, and you shouldn’t need to.successful_payment handler should check whether the order was already fulfilled before granting access a second time.Treat this list as a minimum bar, not a complete security review — if you’re processing meaningful payment volume, it’s worth a dedicated review pass against the Telegram Bot API documentation and your payment provider’s own integration checklist.
Monitoring and Debugging Telegram Bot Payments
Because the payment flow spans three systems — your bot, Telegram, and the provider — debugging failures means knowing where to look first. Most issues fall into one of three categories: the invoice never renders (usually a malformed prices array or an invalid currency code), the pre-checkout step times out (usually a slow or crashing handler), or the payment succeeds on the provider side but your bot never records it (usually a webhook delivery or idempotency bug).
Structured logging around each of the three callback stages — invoice sent, pre-checkout answered, payment confirmed — makes these failures much easier to trace than trying to reconstruct the sequence after the fact. If your bot runs as a containerized service, standard container log tooling is usually sufficient; the same debugging habits used for any other webhook-driven service apply here.
Deploying the Bot: Webhook vs Long Polling
A telegram payments bot can receive updates either via long polling or via a registered webhook. For payment flows specifically, a webhook is almost always the better choice: it reduces the latency between Telegram sending a pre_checkout_query and your bot responding, which matters given the tight response window.
A webhook needs a publicly reachable HTTPS endpoint with a valid TLS certificate — Telegram will not deliver updates to plain HTTP or self-signed certs without extra configuration. A typical production stack looks like:
/webhook/<secret_path>Minimal Docker Compose Setup
Running the bot alongside its database in containers keeps the deployment reproducible and easy to redeploy on a fresh VPS. Here is a minimal docker-compose.yml for a webhook-based telegram payments bot:
version: "3.9"
services:
bot:
build: .
restart: unless-stopped
environment:
- BOT_TOKEN=${BOT_TOKEN}
- PROVIDER_TOKEN=${PROVIDER_TOKEN}
- WEBHOOK_SECRET=${WEBHOOK_SECRET}
- DATABASE_URL=postgres://bot:bot@db:5432/payments
depends_on:
- db
ports:
- "8443:8443"
db:
image: postgres:16
restart: unless-stopped
environment:
- POSTGRES_USER=bot
- POSTGRES_PASSWORD=bot
- POSTGRES_DB=payments
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:If you’re new to the Compose file format or want a refresher on managing environment variables and secrets safely, our guides on managing Compose environment variables and secure secrets handling cover the same patterns used here. For the Postgres container specifically, see our dedicated Postgres Docker Compose setup guide.
Setting the Webhook
Once your container is reachable over HTTPS, register the webhook with a single API call:
curl -F "url=https://yourdomain.com/webhook/${WEBHOOK_SECRET}"
"https://api.telegram.org/bot${BOT_TOKEN}/setWebhook"Verify it landed correctly with getWebhookInfo, which reports the last delivery error if Telegram couldn’t reach your endpoint — this is the first thing to check when a telegram payments bot silently stops receiving invoices.
Scaling and Hosting Considerations
A telegram payments bot handling a handful of orders a day can run comfortably on a small VPS, but as volume grows you’ll want to separate concerns: the webhook receiver should stay lightweight and hand off slower work (fulfillment, email receipts, CRM updates) to a background queue rather than blocking the pre-checkout response.
Common hosting choices for this kind of workload include:
If you’re choosing infrastructure for the first time, a provider like DigitalOcean offers straightforward VPS instances that are a reasonable starting point for a webhook-driven bot before you need anything more elaborate. Whatever you choose, make sure your reverse proxy and TLS certificates are automated (e.g., via Let’s Encrypt) so certificate expiry never silently breaks the webhook Telegram depends on.
Monitoring Payment Health
Beyond application logs, track a few operational signals specific to payments: pre-checkout response latency (should stay well under Telegram’s timeout), failed vs. successful payment ratio, and webhook delivery errors from getWebhookInfo. A sudden spike in pre-checkout rejections often points to a stale price cache or a provider outage rather than a bot bug, so alerting on that ratio separately from generic uptime checks pays off quickly.
FAQ
Do I need a business account to use Telegram bot payments?
Requirements depend on the payment provider you connect, not Telegram itself. Stripe and most regional providers require a verified business or individual account capable of accepting card payments before they’ll issue a live provider token.
Can I accept cryptocurrency through Telegram bot payments?
The native sendInvoice flow is built around card-based payment providers. Crypto payments are typically handled outside this flow, through a separate integration with a crypto payment processor and custom bot commands.
What currencies does telegram bot payments support?
Supported currencies depend entirely on which provider you connect through BotFather. Most major providers support a wide range of standard ISO currency codes, but you should confirm the exact list with your specific provider before launch.
Why does my pre_checkout_query keep failing silently?
This almost always means the handler isn’t responding within Telegram’s timeout window, or it’s throwing an unhandled exception before calling answer(). Add explicit error handling around the handler and confirm it always calls answer(), even in failure cases.
Conclusion
Telegram bot payments give you a fast, native way to charge users without building a custom checkout experience. The mechanics are straightforward once you understand the three-event flow — invoice, pre-checkout, successful payment — but production reliability comes down to the details: secret management, idempotent fulfillment, and fast, defensive pre-checkout handling. Get those right, and telegram bot payments become a small, maintainable piece of a larger bot rather than a fragile bolt-on.