Collect VietQR Payments in Telegram Bots with AgentPay AgentPay VN, an open-source Python SDK, enables Telegram bots to collect VietQR payments directly to a merchant's bank account without intermediaries. The MIT-licensed tool generates QR codes for instant peer-to-peer payments via Vietnamese banking apps, addressing high fees and integration complexity of traditional payment gateways. You've built a Telegram bot that sells digital courses, takes coffee orders, or offers freelance services. Traffic is flowing. But when your bot tries to collect payment, you hit a wall: A founder we know spent two weeks wrestling with Stripe's Telegram integration, only to discover the monthly fee ate 40% of his margins on $2–5 transactions. He needed something lighter, faster, and truly peer-to-peer. Enter AgentPay VN : an open-source Python SDK that lets your Telegram bot generate QR codes pointing directly to your bank account. No middleman. No holding funds. Just instant VietQR payments via the banking system Vietnameses already use daily. AgentPay VN is an MIT-licensed Python SDK + MCP server that orchestrates VietQR payment requests. Here's the mental model: The key: AgentPay never touches money . The QR points straight at your merchant bank account. A bank feed confirms settlement. You own the transaction end-to-end. Telegram has 180+ million users , with especially strong adoption in Southeast Asia. Vietnamese merchants already use banking apps MB Bank, Techcombank, VCB that natively support VietQR scanning. Your bot becomes a natural extension of their daily workflow: No authentication screens. No signup. Pure banking rails. pip install agentpay-vn Verify the installation: python python -c "import agentpay; print agentpay. version " You'll need: For testing, AgentPay provides a sandbox environment. Check the official docs https://agentpay.servicesai.vn/v1/docs for your bank. export AGENTPAY MERCHANT ID="your merchant id" export AGENTPAY API KEY="your api key" export TELEGRAM BOT TOKEN="your telegram token" Here's a minimal Telegram bot that collects a payment: python import os from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import Application, CommandHandler, ContextTypes from agentpay import AgentPayClient Initialize AgentPay agentpay client = AgentPayClient merchant id=os.getenv "AGENTPAY MERCHANT ID" , api key=os.getenv "AGENTPAY API KEY" , async def start update: Update, context: ContextTypes.DEFAULT TYPE - None: """Send welcome message with a /buy command.""" await update.message.reply text "🎉 Welcome Use /buy to purchase an item.\n" "Type /help for more info." async def buy update: Update, context: ContextTypes.DEFAULT TYPE - None: """Create a payment request and send checkout link.""" user id = update.effective user.id Step 1: Create a payment request This tells AgentPay: "I want 50,000 VND from user X" payment request = agentpay client.create payment request amount=50000, VND currency="VND", merchant ref id=f"order {user id} {int time.time }", description="Premium Course - Python Mastery", metadata={"user id": user id, "product": "course python"}, Step 2: Get the checkout URL with embedded QR checkout url = payment request.get "checkout url" payment id = payment request.get "payment id" Step 3: Send to user with inline button keyboard = InlineKeyboardMarkup InlineKeyboardButton "💳 Pay with VietQR", url=checkout url await update.message.reply text f"📦 Order Summary:\n" f"Product: Premium Course\n" f"Price: 50,000 VND\n\n" f"Tap the button below to pay with your banking app.", reply markup=keyboard Store payment id for later confirmation context.user data "pending payment id" = payment id async def check payment update: Update, context: ContextTypes.DEFAULT TYPE - None: """Poll for payment settlement in production, use webhooks .""" payment id = context.user data.get "pending payment id" if not payment id: await update.message.reply text "No pending payment found." return Step 3: Await settlement confirmation In production, listen to bank webhooks instead of polling status = agentpay client.await settlement payment id=payment id, timeout=300, Wait max 5 minutes if status "settled" : await update.message.reply text f"✅ Payment confirmed \n" f"Amount: {status 'amount' :,} VND\n" f"Your premium course access is now active.\n" f"📚 Open Course https://example.com/course " Grant access to course, send API key, etc. else: await update.message.reply text "⏳ Payment not yet confirmed. Try again in a moment." def main : """Start the bot.""" app = Application.builder .token os.getenv "TELEGRAM BOT TOKEN" .build app.add handler CommandHandler "start", start app.add handler CommandHandler "buy", buy app.add handler CommandHandler "check", check payment print "🤖 Bot running..." app.run polling if name == " main ": import time main Line-by-line breakdown: /start sends a welcome message /buy creates a payment request with amount, reference ID, and metadata /check polls for settlement status use webhooks in production Polling is fine for demos, but slow and unreliable. Use bank webhooks to get instant payment confirmation: python from flask import Flask, request, jsonify app = Flask name @app.route "/webhook/agentpay", methods= "POST" def handle payment webhook : """AgentPay calls this when payment settles.""" payload = request.json Verify the signature AgentPay docs explain this if not agentpay client.verify webhook signature payload, request.headers.get "X-Signature" : return {"error": "Invalid signature"}, 401 payment id = payload "payment id" status = payload "status" "settled" or "failed" amount = payload "amount" merchant ref id = payload "merchant ref id" if status == "settled": Extract user ID from merchant ref id user id = int merchant ref id.split " " 1 Grant access to the user e.g., send them an API key, activate subscription, etc. grant access user id Notify user via Telegram asyncio.run send telegram message user id, f"✅ Payment received {amount:,} VND \n" "Your access is active." return {"status": "ok"}, 200 if name == " main ": app.run host="0.0.0.0", port=5000 Configure your webhook URL in the AgentPay dashboard to https://yourdomain.com/webhook/agentpay . If you're using Claude as your AI agent orchestrator, install the MCP server: pip install agentpay-mcp Configure Claude's MCP settings: { "mcpServers": { "agentpay": { "command": "agentpay-mcp", "env": { "AGENTPAY MERCHANT ID": "your merchant id", "AGENTPAY API KEY": "your api key" } } } } Now Claude can call AgentPay directly: User: "I want to sell a course for 200,000 VND." Claude: I'll create a payment request for you. Calls agentpay.create payment request Claude: Payment link: https://checkout.agentpay.vn/... Imagine a café selling espresso shots via Telegram: /order → "1x Espresso 40,000 VND "The entire flow takes 30 seconds. No payment processor fees. No settlement delays. Always include a unique merchant ref id to prevent duplicate charges if the network retries: python import uuid merchant ref id = f"order {user id} {uuid.uuid4 }" Not all webhooks arrive instantly. Implement retry logic: python from tenacity import retry, stop after attempt, wait exponential @retry stop=stop after attempt 5 , wait=wait exponential async def notify user via telegram user id, message : Attempt up to 5 times with exponential backoff await bot.send message user id, message Use a database PostgreSQL, MongoDB to track payment status: class PaymentRecord db.Model : payment id = db.Column db.String, primary key=True user id = db.Column db.Integer amount = db.Column db.Integer VND status = db.Column db.String pending, settled, failed created at = db.Column db.DateTime, default=datetime.now AgentPay provides a sandbox environment. Always test before going live: agentpay client = AgentPayClient merchant id="sandbox merchant id", api key="sandbox api key", environment="sandbox", Switch to "production" later | ✅ Do | ❌ Don't | |---|---| | Use webhook callbacks for payment confirmation | Poll the API in a tight loop | | Store merchant ref id; match it in webhook | Trust the order of webhook events | | Verify webhook signatures | Skip signature verification | | Implement idempotent request IDs | Assume network calls always succeed | | Start with sandbox environment | Go live without testing | | Monitor settlement times | Assume instant settlement usually seconds, but be safe | | Log all payment events | Ignore payment failures silently | Q: Can AgentPay handle payments in other currencies USD, etc. ? A: Currently, AgentPay VN is designed for VND Vietnamese Dong via VietQR, which is a Vietnamese banking standard. International currency support would require additional bank partnerships. Q: What if the customer's bank doesn't support VietQR? A: Most Vietnamese banks MB, Vietcombank, Techcombank, ACB, VP Bank, etc. support VietQR. If a customer's bank doesn't, they can ask their bank to enable it, or you can provide a fallback e.g., direct bank transfer details . Q: How much does AgentPay cost? A: AgentPay itself is free MIT open-source . You pay your bank's standard VietQR transaction fees typically 0–0.5% , which is much cheaper than Stripe 2.9% + $0.30 or PayPal 3.5% . Q: How long does settlement take? A: Usually 1–5 seconds. The money goes directly to your bank account, so it's as fast as an interbank transfer. Some banks may batch settlements end-of-day, but that's rare. pip install agentpay-vn and get your first payment in under 10 minutes pip install agentpay-vn Your Telegram payment bot is minutes away. No more payment processor headaches. Just you, your customers, and the Vietnamese banking system doing what it does best.