← Blog/Developer

Building a Telegram Bot That Accepts Crypto Payments

Mar 28, 2026 · 10 min read

Full tutorial: create invoices, send payment addresses to users, handle webhooks, and deliver digital goods automatically on confirmation.

Telegram bots are a popular distribution channel for digital goods, VPN subscriptions, proxy services, and premium content. Accepting crypto payments directly in a bot eliminates friction: the user stays in Telegram, pays with their crypto wallet, and receives access automatically — no external checkout page required.

Architecture Overview

  • ✓User sends /buy command to the bot
  • ✓Bot calls Bekena API to create a payment invoice
  • ✓Bot sends the USDT address + amount to the user in Telegram
  • ✓User pays from their wallet
  • ✓Bekena sends a payment.confirmed webhook to your server
  • ✓Server delivers the product (sends credentials, enables access, etc.)
  • ✓Bot sends a confirmation message to the user

Setting Up the Bot

Create a bot with @BotFather on Telegram, get your bot token, and set up a webhook so Telegram sends messages to your server. You'll need an HTTPS endpoint — Telegram requires SSL for webhooks.

Creating a Payment Invoice

typescript
import TelegramBot from 'node-telegram-bot-api'; const bot = new TelegramBot(process.env.TG_TOKEN!, { polling: false }); async function handleBuyCommand(chatId: number, userId: number) { const invoice = await bekena.createPayment({ amount: '9.99', currency: 'USDT_TRC20', order_id: `tg_${userId}_${Date.now()}`, metadata: { telegram_user_id: userId }, webhook_url: process.env.WEBHOOK_URL!, expires_in: 3600, // 1 hour }); await bot.sendMessage(chatId, [ '💳 *Payment Invoice*', '', `Send exactly *${invoice.amount} USDT TRC20* to:`, `\`${invoice.address}\``, '', `⏱ Expires in 60 minutes`, `🔗 [Track on Tronscan](https://tronscan.org/#/address/${invoice.address})`, ].join('\n'), { parse_mode: 'Markdown' }); }

Handling the Payment Webhook

typescript
app.post('/bekena-webhook', async (req, res) => { // Verify signature if (!verifySignature(req.body, req.headers['x-bekena-sig'])) { return res.status(401).end(); } const { event, data } = JSON.parse(req.body); if (event === 'payment.confirmed') { const userId = data.metadata.telegram_user_id; // Activate access in your database await db.users.update(userId, { subscription_active: true, expires_at: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), }); // Notify user in Telegram await bot.sendMessage(userId, [ '✅ *Payment confirmed!*', '', 'Your subscription is now active for 30 days.', 'Use /panel to access your dashboard.', ].join('\n'), { parse_mode: 'Markdown' }); } res.json({ received: true }); });

Handling Expired Invoices

When an invoice expires without payment, Bekena sends a payment.expired webhook. Send the user a message letting them know the payment window closed and provide a /buy command to generate a new invoice. Keep your invoice expiry reasonable — 30–60 minutes gives users enough time without leaving addresses active indefinitely.

User Experience Tips

  • ✓Always show the exact amount and network (never just "send USDT")
  • ✓Include a QR code for the payment address — use a QR library or Bekena's hosted invoice page
  • ✓Add a "Check payment" button that polls the Bekena API for status
  • ✓Send a reminder message after 45 minutes if payment hasn't confirmed yet
  • ✓Keep transaction records for support queries — users sometimes send to wrong address

Ready to accept crypto payments?

Start with a free sandbox account

Create Free Account →

Related articles

Developer

How to Properly Verify Bekena Webhooks (With Code Examples)

Developer

Understanding Idempotency Keys in Payment APIs

Guide

Complete Guide to Accepting USDT Payments for Your Business