Skip to Content
GuidesTelegram Bot

Accept crypto payments in your Telegram bot

This guide walks you through accepting USDC/USDT payments inside a Telegram bot using the Inzi API.

What you’ll build:

  • User taps “Pay” in your bot
  • Bot creates an Inzi checkout
  • User pays in crypto on the hosted checkout page
  • Your bot receives a webhook and fulfills the order

Get API keys

  1. Sign up at inzipay.com 
  2. Go to Settings → API Keys and generate a test key (sk_test_...)
  3. Copy your Webhook Secret from Settings → Webhook

Create checkout when user taps “Pay”

When a user initiates a payment, create a checkout on your backend:

import { Bot, InlineKeyboard } from 'grammy' const INZI_KEY = process.env.INZI_API_KEY // sk_test_... or sk_live_... bot.command('pay', async (ctx) => { const amount = ctx.match || '10.00' const userId = String(ctx.from.id) // Create Inzi checkout const res = await fetch('https://api.inzilink.com/api/v1/checkouts', { method: 'POST', headers: { 'Authorization': `Bearer ${INZI_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ amount, currency: 'USD', description: `Top-up $${amount}`, metadata: { user_id: userId, type: 'topup', telegram_chat_id: String(ctx.chat.id), }, webhook_url: 'https://yourbot.com/webhooks/inzi', expires_in: 1800, }), }) const { checkout_url } = await res.json() // Send payment button const keyboard = new InlineKeyboard() .url('Pay now', checkout_url) await ctx.reply(`Pay $${amount} with crypto:`, { reply_markup: keyboard, }) })

The checkout page works inside Telegram’s built-in browser. Users select a chain (TON, Polygon, etc.), see a QR code + address, and pay from any wallet.

Handle the webhook

When payment is confirmed, Inzi sends a checkout.completed webhook to your server:

import express from 'express' import crypto from 'crypto' const app = express() app.use('/webhooks/inzi', express.raw({ type: 'application/json' })) const WEBHOOK_SECRET = process.env.INZI_WEBHOOK_SECRET app.post('/webhooks/inzi', async (req, res) => { // Verify signature const timestamp = req.headers['x-inzi-timestamp'] const signature = req.headers['x-inzi-signature'].replace('sha256=', '') const signedPayload = `${timestamp}.${req.body.toString()}` const expected = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(signedPayload) .digest('hex') if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))) { return res.status(401).send('Invalid signature') } const event = JSON.parse(req.body.toString()) if (event.event === 'checkout.completed') { const { user_id, telegram_chat_id } = event.data.metadata const amount = event.data.amount // Credit user balance in your database await creditBalance(user_id, parseFloat(amount)) // Notify user in Telegram await bot.api.sendMessage( telegram_chat_id, `Payment of $${amount} received! Your balance has been updated.` ) } res.json({ ok: true }) })

Test the flow

  1. Use sk_test_ key — mock webhook fires in 5 seconds
  2. Send /pay 10 to your bot
  3. Tap “Pay now” — see the checkout page
  4. Your webhook endpoint receives checkout.completed
  5. Bot sends confirmation message

Go live

Switch to sk_live_ and update your webhook URL to production.

Telegram WebApp support: The checkout page detects Telegram’s WebView and calls Telegram.WebApp.close() after payment, returning the user to your bot.