Telegram Bot Payments: A Developer’s Guide to Accepting Payments in Bots

Telegram bot payments let you sell digital goods, subscriptions, or services directly inside a chat, without redirecting users to a separate checkout page.

Ready to use

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.txt

Jump to the full context

On this page
  1. What Are Telegram Bot Payments and How They Work
  2. The Three Payment Events You Must Handle
  3. Setting Up Telegram Bot Payments With BotFather
  4. Registering a Payment Provider Token
  5. Testing With Stripe's Test Mode
  6. Implementing the Payment Flow in Your Bot
  7. Handling send_invoice, precheckout_query, and successful_payment
  8. Automating Order Fulfillment With n8n
  9. Securing Telegram Bot Payments in Production
  10. Monitoring and Debugging Telegram Bot Payments
  11. Deploying the Bot: Webhook vs Long Polling
  12. Minimal Docker Compose Setup
  13. Setting the Webhook
  14. Scaling and Hosting Considerations
  15. Monitoring Payment Health
  16. FAQ
  17. Conclusion

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:

  • The bot server — your application code that sends invoices and reacts to payment events.
  • Telegram’s Bot API — routes messages, renders the payment sheet, and forwards events to your webhook or long-polling loop.
  • The payment provider — the entity that actually authorizes and captures the charge (Stripe, or a regional provider depending on your country).
  • 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.txt

    Testing 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:

  • The bot’s successful_payment_callback posts the payment payload to an n8n webhook.
  • An n8n workflow validates the payload, writes a row to a spreadsheet or database, and grants the purchased access.
  • A separate branch sends a formatted receipt back through the Telegram Bot API or by email.
  • 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:

  • Never trust the client-side payload. Always re-validate price and item availability inside pre_checkout_query, not just at invoice-creation time — prices or stock can change between the two events.
  • Store provider tokens and bot tokens as secrets, not environment variables baked into an image, and rotate them if you suspect exposure.
  • Log payment events with enough detail to reconcile disputes, including the Telegram 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.
  • Use HTTPS with a valid certificate for any webhook endpoint that receives Telegram updates; Telegram will refuse to deliver updates to a webhook that fails certificate validation.
  • Idempotency matters. Telegram can, in rare network conditions, redeliver an update. Your 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:

  • A reverse proxy (Nginx or Caddy) terminating TLS
  • Your bot application container handling /webhook/<secret_path>
  • A database (Postgres or Redis) for idempotency keys and order state
  • A queue or background worker for anything slower than the pre-checkout timeout allows
  • 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:

  • A single VPS running Docker Compose for low-to-medium volume bots
  • A managed container platform if you already run other services there
  • Redis or a lightweight message queue for decoupling webhook handling from fulfillment logic — see our Redis Docker Compose guide if you need a reference setup
  • 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.