Add VietQR Checkout to Your LLM Agent in 10 Minutes
The Problem: Your AI Agent Can't Close the Sale
You've built an impressive AI agent—it answers questions, recommends products, even negotiates terms. But the moment a customer says "I'm ready to buy," your agent hits a wall. It can describe your course, but can't collect payment. It can schedule consultations, but can't charge the booking fee. The conversation breaks, the user jumps to another tab to pay via your website, and you've lost the seamless experience that made them trust your agent in the first place.
This is a real bottleneck for AI-first businesses in Vietnam. Most LLM frameworks don't have native Vietnamese payment support. Building it from scratch means wrestling with bank APIs, compliance, and settlement complexity.
Until now.
AgentPay VN solves this in three lines of code. In the next 10 minutes, you'll add a real, working checkout to your agent that points straight to your bank account—no middleman, no holding funds, no black box.
What Is AgentPay VN?
AgentPay VN is an open-source (MIT license) Python SDK + MCP server that lets AI agents create and track VietQR payments. Here's what makes it different:
- Zero fund holding: The QR code points directly to your merchant bank account. AgentPay never touches the money.
- Settlement confirmation: A bank feed tells your agent the instant a payment lands.
- Agent-native: Built for Claude, ChatGPT, and custom LLM agents. Works with the Model Context Protocol.
- Lightweight: ~50 lines of Python to go live.
- Open source: Inspect every line at github.com/phuocdu/agentpay-vn.
It's not a payment processor—it's a bridge between your agent and Vietnamese banking infrastructure.
Installation: One Command
pip install agentpay-vn
That's it. No environment variables yet, no account creation rituals. AgentPay VN is designed to work with your existing bank details (you supply those later).
The 3-Step Flow Your Agent Will Use
Step 1: Create a Payment Request
Your agent calls create_payment_request() with an amount and description.
Step 2: Send the Checkout URL
AgentPay returns a URL with an embedded VietQR code. Your agent sends this to the user (via chat, email, or a button).
Step 3: Await Settlement
Your agent calls await_settlement() and blocks until the payment lands in your bank account. Once confirmed, it continues (deliver the product, send the API key, start the course, etc.).
No polling, no webhooks to manage, no guessing if the user actually paid.
Build Your First Payment-Enabled Agent
Step 1: Set Up Your Bank Account
You need a Vietnamese bank account with VietQR support. Almost every major bank (VPBank, Techcombank, MB, Vietcombank) supports it. AgentPay VN works with any of them. Here's what you'll provide to the SDK:
- Bank account number
- Account holder name
- Bank short code (e.g.,
vpbank,tcb)
See the full docs for your bank's code.
Step 2: Write the Agent Code
Here's a minimal example: a course-selling agent that collects payment before sending the course link.
from agentpay_vn import create_payment_request, await_settlement
import asyncio
# Initialize with your bank details
from agentpay_vn import AgentPay
agent_pay = AgentPay(
bank_account="1234567890",
account_holder="Phuoc Du",
bank_code="vpbank"
)
async def sell_course(student_name: str, course_price: int = 299000):
"""
Sells a course via VietQR. Agent flow:
1. Create payment request
2. Show QR to student
3. Wait for settlement
4. Deliver course access
"""
# Step 1: Create the payment request
payment = await agent_pay.create_payment_request(
amount=course_price,
description=f"Python Course - {student_name}",
order_id=f"course_{student_name}_{int(time.time())}"
)
print(f"\n✨ Payment request created!")
print(f"Checkout URL: {payment['checkout_url']}")
print(f"QR Code: {payment['qr_code_url']}")
print(f"Amount: {course_price:,} VND\n")
# Step 2: In a real agent, you'd send this URL to the user here
# agent.send_to_user(payment['checkout_url'])
# Step 3: Wait for settlement (blocks until payment confirmed)
print("⏳ Waiting for payment confirmation...")
settlement = await agent_pay.await_settlement(
order_id=payment['order_id'],
timeout_seconds=300 # Wait max 5 minutes
)
if settlement['status'] == 'confirmed':
print(f"✅ Payment confirmed! {settlement['amount']:,} VND received.")
print(f"Settlement time: {settlement['settled_at']}")
# Deliver the course
return {
"success": True,
"message": f"Welcome to the course, {student_name}!",
"course_link": "https://your-course-platform.com/access?token=abc123",
"transaction_id": settlement['transaction_id']
}
else:
return {
"success": False,
"message": "Payment not confirmed. Try again."
}
# Run it
result = asyncio.run(sell_course("Nguyen Tuan"))
print(result)
Line-by-line breakdown:
- Lines 1-10: Import AgentPay and initialize with your bank details. This tells AgentPay where to route the QR code.
- Lines 13-20: Define the main agent function that sells a course.
- Lines 25-31: Create a payment request. You provide the amount, a description (for the bank statement), and a unique order ID. AgentPay returns a
checkout_url(for web) andqr_code_url(for mobile/in-app). - Lines 36-39: In production, your agent would send this URL to the user. For testing, we just print it.
- Lines 41-46:
await_settlement()blocks until the payment lands in your bank account. It checks the bank feed every few seconds. The timeout defaults to 600 seconds (10 minutes) but you can customize it. - Lines 48-57: Once confirmed, deliver the product (course link, API key, license, whatever). The settlement object includes the exact timestamp and transaction ID for your records.
Step 3: Integrate with Claude (or Your LLM Framework)
To make this work with Claude and the Model Context Protocol, create an MCP configuration:
{
"mcpServers": {
"agentpay": {
"command": "agentpay-mcp",
"env": {
"AGENTPAY_BANK_ACCOUNT": "1234567890",
"AGENTPAY_ACCOUNT_HOLDER": "Phuoc Du",
"AGENTPAY_BANK_CODE": "vpbank"
}
}
}
}
Place this in your Claude client config (or your custom agent framework). The MCP server exposes three tools:
create_payment_request(amount, description, order_id)→ returnscheckout_urlawait_settlement(order_id, timeout_seconds)→ blocks, returns settlement statusget_payment_status(order_id)→ non-blocking status check
Now Claude can call these tools directly in its reasoning loop. Here's a system prompt snippet:
You are a course assistant. When a user wants to buy a course:
1. Call create_payment_request with the course price.
2. Send the checkout_url to the user via chat.
3. Wait for the user to confirm they've paid, then call await_settlement.
4. Once confirmed, provide the course access link.
Never share the QR code image directly; always use the checkout_url so users can pay from their phone.
Claude will now handle the entire sales flow autonomously.
Real-World Example: A Café's Loyalty Bot
Imagine a coffee café in Hanoi with a Telegram bot that recommends drinks and sells loyalty cards.
The old way: Bot says "You can buy a 500k loyalty card," but the conversation ends. Customer leaves the chat, visits the café's website, pays, comes back confused.
With AgentPay VN: Bot says "You can buy a 500k loyalty card for 10% off your next 10 drinks," → creates payment → sends VietQR → waits 30 seconds → payment lands → bot immediately sends the customer a QR code to scan at the register for discount. The entire flow happens in the chat, in under a minute, with zero friction.
Code snapshot:
async def buy_loyalty_card(user_id: str, card_tier: str = "gold"):
prices = {"silver": 200000, "gold": 500000, "platinum": 1000000}
amount = prices[card_tier]
# Create payment
payment = await agent_pay.create_payment_request(
amount=amount,
description=f"{card_tier.upper()} Loyalty Card - Café Hanoi",
order_id=f"card_{user_id}_{card_tier}"
)
# Send to user
await telegram_bot.send_message(
user_id,
f"Your {card_tier} card costs {amount:,} VND.\n"
f"Scan this QR: {payment['qr_code_url']}\n"
f"I'll activate your card the moment you pay."
)
# Wait for settlement
settlement = await agent_pay.await_settlement(payment['order_id'])
if settlement['status'] == 'confirmed':
# Create discount code
code = generate_code(user_id, card_tier)
await telegram_bot.send_message(
user_id,
f"🎉 Done! Your code: {code}\nShow this at the register."
)
save_loyalty_card(user_id, card_tier, code, settlement['transaction_id'])
The bot never holds money, never touches bank details, never has compliance liability. The café's bank statement shows the payment instantly. Perfect.
Do's and Don'ts
| Do | Don't |
|---|---|
| Use real VietQR-enabled bank accounts | Try to fake settlement for testing (use sandbox if available; check docs) |
Set reasonable timeouts (5–10 min) for await_settlement() |
Block forever waiting for payment; log and retry |
Store transaction_id from settlement for reconciliation |
Rely on order ID alone; settlement ID is the source of truth |
| Test with small amounts first (10k VND) | Deploy without testing your bank feed integration |
Use order_id to prevent duplicate payments |
Create multiple requests for the same user without checking status first |
| Expire payment requests after timeout | Show the same checkout URL indefinitely |
Common Questions
Q: Does AgentPay hold my money? No. The QR code routes payments straight to your bank account. AgentPay only tracks settlement via your bank feed; it never processes or holds funds.
Q: How fast is settlement confirmation? Dependency on your bank, but typically 30 seconds to 2 minutes after the customer's payment. VietQR is instant; the confirmation is just AgentPay checking your bank feed.
Q: Can I use this with multiple bank accounts? Yes. Create multiple AgentPay instances, each with different bank credentials. Useful for multi-vendor platforms.
Q: What if the customer closes the app before paying?
The payment request stays active for the timeout period (default 10 min). If they pay later, await_settlement() will detect it. You can also call get_payment_status() to check without blocking.
Advanced Tips
-
Timeout Strategy: For short-lived interactions (chat), use
timeout_seconds=300(5 min). For longer flows (email-based), usetimeout_seconds=3600(1 hour). -
Retry Logic: If
await_settlement()times out, don't assume the payment failed. Callget_payment_status()first; maybe the bank was slow. -
Idempotency: Always use unique, predictable order IDs (e.g.,
f"user_{user_id}_{int(time.time())}") so you never double-charge. -
Reconciliation: Store
transaction_id(from settlement) in your database, not just the order ID. This is your link to the actual bank record. -
Multi-Currency Simulation: AgentPay works in VND. If you need to quote prices in USD, convert at request time, then pay in VND. Store the exchange rate in your transaction record.
Key Takeaways
- AgentPay VN removes the payment friction from AI agents. In 10 minutes, your agent can collect real VietQR payments.
- You keep full control: Payments go straight to your bank account; AgentPay is just the bridge.
- Three function calls:
create_payment_request()→ send URL →await_settlement(). That's the whole flow. - MCP integration is turnkey: Claude and other agents can call AgentPay tools directly; no custom API layer needed.
- Open source and lightweight: ~50 lines of production code; inspect everything on GitHub.
Get Started Now
- Install:
pip install agentpay-vn - Read the docs: https://agentpay.servicesai.vn/v1/docs
- Star the repo: https://github.com/phuocdu/agentpay-vn
- Build your first agent: Copy the course example above, swap in your bank details, and test with 10k VND.
Your AI agent can close deals now. Go build.