Add VietQR Checkout to Your LLM Agent in 10 Minutes
The Problem: Your AI Agent Can Sell, But Can't Collect Money
Imagine you've built a brilliant AI agent—maybe it tutors Vietnamese students, sells digital courses, or handles café orders. It answers questions perfectly, closes deals smoothly, and users genuinely want to pay. But then what? Your agent sends them a payment link, they leave your chat, and you've lost the conversation thread. No real-time confirmation. No seamless handoff. You're back to the old world of redirects and broken flows.
That friction costs you conversions. According to recent payment data, abandonment rates spike above 20% when users must leave their application context to complete a transaction.
AgentPay VN solves this by embedding direct VietQR payment collection into your agent's conversation loop. No redirects. No money held. Just a QR code that points straight to the merchant's bank account, with instant settlement confirmation. Within 3 lines of code.
Why AgentPay VN Is Different
Before we dive into setup, let's clarify what makes AgentPay VN unique:
- No wallet, no escrow: Money goes directly to your bank account. We never touch it.
- Open source (MIT): Full transparency. Run it yourself on your infrastructure.
- MCP-ready: Plugs into Claude and other AI agents via the Model Context Protocol.
- Bank-verified settlement: Your bank feed confirms the payment arrived—no polling, no guessing.
- Built for VietQR: Optimized for Vietnam's banking ecosystem; works with all major banks.
This is not a payment processor that takes a cut or locks you in. It's a bridge between your agent and your customer's bank.
What You'll Build in 10 Minutes
By the end of this guide, you'll have a working Python agent that:
- Creates a payment request when a user decides to buy
- Generates a checkout URL with an embedded VietQR code
- Waits for settlement confirmation in real time
- Completes the transaction without leaving the chat
We'll show you two implementations: raw SDK (for custom agents) and MCP server (for Claude and compatible platforms).
Step 1: Install AgentPay VN
Start with the Python SDK:
pip install agentpay-vn
If you're running the MCP server (for Claude):
pip install agentpay-mcp
That's it. No secret keys to paste. No OAuth flow. AgentPay VN uses your existing bank connection.
Step 2: The 3-Line Payment Flow
AgentPay VN's core is beautifully simple. Here's the canonical flow:
Creating Your First Payment Request
from agentpay_vn import PaymentClient
# Initialize the client (uses your bank config)
client = PaymentClient()
# 1. Create a payment request
payment_req = client.create_payment_request(
amount=250000, # 250,000 VND
description="Advanced Vietnamese Course - 3 months access",
order_id="course_001_user_42", # Your internal ID
merchant_name="AI Tutors VN"
)
# 2. Send the checkout URL to your user (via chat, SMS, etc.)
checkout_url = payment_req.checkout_url
print(f"Pay here: {checkout_url}")
# 3. Await settlement confirmation
settlement = client.await_settlement(
payment_id=payment_req.payment_id,
timeout_seconds=300 # 5 minutes
)
if settlement.status == "completed":
print(f"✅ Payment confirmed! {settlement.amount} VND received.")
# Grant course access, send invoice, etc.
else:
print("⏱️ Payment pending or failed.")
Line-by-line explanation:
- Line 1–2: Import and initialize. AgentPay VN auto-detects your bank config from environment or local setup.
- Line 5–10:
create_payment_request()generates a unique payment with your amount, description, and order ID. This is what your customer sees. - Line 12–13: The
checkout_urlis a live QR code page. Share it via Telegram, WhatsApp, or embed it in your chat UI. - Line 15–17:
await_settlement()is a blocking call that waits for your bank to confirm the deposit. It polls your bank feed (or uses webhooks if configured). - Line 19–23: On settlement, you have proof. Grant access, send invoice, trigger workflows—all within the agent's conversation.
Real-World Example: A Course-Selling Bot
Let's say you're running an AI tutor that sells a 3-month Vietnamese writing course.
import asyncio
from agentpay_vn import PaymentClient
client = PaymentClient()
async def sell_course(user_id: str, course_tier: str):
"""Handle course purchase from chat."""
prices = {
"basic": 150000, # 150k VND
"premium": 350000, # 350k VND
"vip": 750000 # 750k VND
}
amount = prices.get(course_tier, 150000)
# Step 1: Create the request
payment = client.create_payment_request(
amount=amount,
description=f"Vietnamese Writing - {course_tier.title()} Tier",
order_id=f"course_{user_id}_{course_tier}",
merchant_name="AI Writing Tutor"
)
# Step 2: Tell the user
print(f"🎓 Course access: {payment.checkout_url}")
print(f"Amount: {amount:,} VND")
print("Scan the QR or click the link. Settlement confirmed within 30 seconds.\n")
# Step 3: Wait for payment
try:
settlement = client.await_settlement(
payment_id=payment.payment_id,
timeout_seconds=300
)
if settlement.status == "completed":
# Grant access immediately
grant_course_access(user_id, course_tier)
send_invoice(user_id, amount, settlement.transaction_id)
print(f"✅ Welcome! Your {course_tier} tier is unlocked.")
return True
except TimeoutError:
print("⏰ Payment window closed. Create a new request to try again.")
return False
def grant_course_access(user_id: str, tier: str):
# Your logic: update DB, send link, etc.
print(f"[DB] User {user_id} granted access: {tier}")
def send_invoice(user_id: str, amount: int, txn_id: str):
# Your logic: email invoice
print(f"[EMAIL] Invoice sent to user {user_id} | TXN: {txn_id}")
# Run it
asyncio.run(sell_course("user_abc_123", "premium"))
Notice how the entire transaction stays within one function. No redirect. No separate payment page. The user scans, pays, and the bot immediately confirms and unlocks the course.
Step 3: Integrate with Claude via MCP Server
If you're building an agent for Claude or another MCP-compatible platform, expose AgentPay VN as a tool:
MCP Server Configuration
Create agentpay_mcp_config.json:
{
"name": "agentpay-vn",
"version": "1.0.0",
"tools": [
{
"name": "create_payment",
"description": "Create a VietQR payment request. Returns checkout URL and payment ID.",
"inputSchema": {
"type": "object",
"properties": {
"amount": {
"type": "number",
"description": "Amount in VND (e.g., 250000 for 250k)"
},
"description": {
"type": "string",
"description": "What the customer is buying"
},
"order_id": {
"type": "string",
"description": "Your internal reference ID"
},
"merchant_name": {
"type": "string",
"description": "Your business name"
}
},
"required": ["amount", "description", "order_id"]
}
},
{
"name": "check_payment_status",
"description": "Check if a payment has been settled.",
"inputSchema": {
"type": "object",
"properties": {
"payment_id": {
"type": "string",
"description": "Payment ID from create_payment"
}
},
"required": ["payment_id"]
}
}
]
}
Start the MCP server:
agentpay-mcp --config agentpay_mcp_config.json
Now Claude (or your AI agent) can call create_payment directly in its response:
Claude's capability:
"I've prepared a 3-month premium course for you. The cost is 350,000 VND. Let me generate a payment link..."
Claude calls: `create_payment(amount=350000, description="Premium Vietnamese Course - 3 months", order_id="user_xyz_premium", merchant_name="AI Tutors")
"Great! Scan this QR code or click here to pay. Your access will activate instantly after confirmation."
The agent never leaves the conversation. The user never leaves the app. Settlement happens in the background with bank-level confirmation.
Real-World Walkthrough: An Online Café Menu Bot
Let's say you're running a café in Hà Nội and built an AI agent to handle remote orders:
Scenario
Customer on WhatsApp:
"Hi! I want 2 cappuccinos and 1 matcha latte for delivery tomorrow at 10 AM."
Agent (powered by AgentPay VN):
- Confirms order: 2 cappuccinos (100k each) + 1 matcha (80k) = 280k VND
- Calls
create_payment_request()with order details - Sends checkout URL: "Pay here to confirm your 10 AM delivery: [QR + link]"
- Calls
await_settlement()(waits max 5 minutes) - On confirmation: - Marks order as paid in kitchen system - Sends: "✅ Payment confirmed! Your order is being prepared. Delivery at 10 AM to [address]. Thank you!" - SMS reminder sent to driver
- On failure or timeout: - "Payment not received. Your order is reserved for 10 more minutes. Resend payment link if needed."
Result: No manual intervention. No customer confusion. Orders flow directly from chat → payment → kitchen → delivery.
Do's and Don'ts
| Do | Don't |
|---|---|
Create a new payment_id per customer (never reuse) |
Don't store bank credentials in your agent code |
Use order_id to track your internal business logic |
Don't assume settlement is instant—use await_settlement() to wait |
Set realistic timeout_seconds (300-600 for most UX flows) |
Don't create payments without confirming the customer's intent first |
| Test with the sandbox first (if available) | Don't ignore settlement failures—always handle the exception |
Log transaction_id for reconciliation |
Don't poll the API repeatedly; use webhooks or await_settlement() |
Advanced Tips: Production Hardening
Idempotency: Retry Without Duplicating
If your agent crashes mid-payment, don't create a duplicate request. Use idempotency keys:
payment = client.create_payment_request(
amount=250000,
description="Course Access",
order_id="course_user_42",
idempotency_key="order_course_user_42_v1" # Same key = same result
)
Webhook Notifications (Not Just Polling)
Instead of blocking with await_settlement(), register a webhook:
client.register_webhook(
url="https://yourserver.com/agentpay/webhook",
events=["settlement.completed", "settlement.failed"]
)
Your server receives a POST when payment settles. Respond with HTTP 200 to acknowledge. This scales better than polling.
Error Handling in Production
try:
settlement = client.await_settlement(payment_id, timeout_seconds=300)
except PaymentTimeoutError:
# Payment window closed; offer retry
log_event(f"Payment {payment_id} timed out")
except PaymentFailedError as e:
# Bank rejected or customer cancelled
log_event(f"Payment failed: {e.reason}")
except Exception as e:
# Network error, config issue, etc.
log_event(f"Unexpected error: {e}")
# Retry logic here
FAQ
Q: Does AgentPay VN take a fee? A: No. AgentPay VN is open-source (MIT) and free to use. It's a bridge, not a payment processor. Your bank may charge standard wire fees, but AgentPay VN doesn't.
Q: Can I use this for international customers? A: Not yet. AgentPay VN is optimized for VietQR and Vietnam's banking system. International payments require a different solution.
Q: What if a customer's payment fails? A: The agent detects the failure (settlement status ≠ "completed") and can offer to retry, refund, or suggest an alternative payment method. You have full control.
Q: How long does settlement take? A: VietQR is nearly instant at the bank level (seconds to minutes). AgentPay VN detects this via bank feed, so your agent can confirm within 30–60 seconds in most cases.
Key Takeaways
- Instant checkout in conversation: No redirects, no lost context. Customer pays within the chat.
- 3-line core flow:
create_payment_request()→await_settlement()→ action. Everything else is configuration. - Money never touches AgentPay VN: It goes straight to your bank. Compliance and trust are built in.
- Open-source and flexible: Run it yourself, customize it, integrate it into any Python agent or MCP-compatible platform.
- VietQR is your friend: Works with all major Vietnamese banks. QR codes are familiar to customers.
- Real production use: Use idempotency keys, webhooks, and proper error handling for reliability.
Next Steps
Ready to add payments to your agent? Here's your path forward:
- Install:
pip install agentpay-vn - Read the docs: https://agentpay.servicesai.vn/v1/docs
- Explore the source: https://github.com/phuocdu/agentpay-vn
- Build your first agent: Use the code examples above as a template.
- Test with a real payment: The fastest way to learn.
Whether you're selling courses, handling café orders, or running a subscription bot, AgentPay VN gets you there in 10 minutes—not 10 days. Your agent can now close the entire transaction loop without leaving the conversation.
Happy building. 🚀