Accept VietQR Payments in Your AI Agent with Python
The Problem: Your AI Agent Can't Actually Get Paid
You've built a brilliant AI agent—maybe it tutors students, manages bookings, or sells digital products. It answers questions perfectly, handles customer inquiries, and even closes deals. But the moment someone says "I want to buy," your agent hits a wall.
Traditional payment APIs require: - Complex PCI compliance overhead - Multiple third-party integrations - Custody of customer funds (compliance nightmare) - Days to set up merchant accounts
In Vietnam, where VietQR is ubiquitous and merchants expect instant bank settlement, this friction is unacceptable. Your AI agent should accept payments directly into your bank account—no middleman, no waiting, no complications.
That's where AgentPay VN enters the picture.
What Is AgentPay VN?
AgentPay VN is an open-source MIT-licensed Python SDK that lets your AI agents collect VietQR payments in three lines of code. Here's what makes it different:
- Zero Fund Custody: The QR code points directly at your merchant's bank account. Your agent never touches the money.
- Instant Settlement Confirmation: A bank feed confirms when payment lands—no polling, no guessing.
- MCP Server Support: Works seamlessly with Claude and other AI frameworks via the Model Context Protocol.
- Production-Ready: MIT licensed, auditable, and designed for real-world Vietnamese payment flows.
The Three-Line Payment Flow
Before we dive into code, understand the core pattern:
1. create_payment_request() → generates a unique payment ID
2. send checkout_url() → delivers VietQR link to customer
3. await_settlement() → waits for bank confirmation
Your agent triggers these steps in response to a customer's intent to purchase. The customer scans the VietQR code with their banking app, transfers money, and your bank confirms receipt.
Installation & Setup
Start with a fresh Python 3.8+ environment:
pip install agentpay-vn
That's genuinely it. No API keys to hunt for, no merchant portal registrations—AgentPay VN uses your existing bank account.
For MCP server mode (recommended for Claude and agentic frameworks):
pip install agentpay-vn
agentpay-mcp # Starts the MCP server on localhost:5000
Real-World Example: A Course-Selling Bot
Let's build a practical scenario: CourseBot, an AI agent that sells programming courses to Vietnamese students. A student asks "Can I buy your Python course?" and CourseBot should:
- Generate a payment request for 299,000 VND
- Send the VietQR checkout link
- Confirm payment and unlock the course
Here's the implementation:
Step 1: Create a Payment Request
from agentpay_vn import AgentPayClient
# Initialize the client
client = AgentPayClient()
# Create a payment request for a course purchase
payment = client.create_payment_request(
amount=299000, # VND
order_id="course_python_101_user_456",
description="Advanced Python Course - CourseBot",
merchant_name="CourseBot Academy",
customer_phone="0901234567", # Optional but recommended
callback_url="https://yourserver.com/payments/callback" # Your webhook
)
print(f"Payment ID: {payment.payment_id}")
print(f"QR Code URL: {payment.qr_url}")
print(f"Amount: {payment.amount} VND")
print(f"Status: {payment.status}") # 'pending'
Line-by-line explanation:
amount=299000: Price in Vietnamese Dong. No currency conversion needed.order_id: Unique identifier linking this payment to your database record. Use a pattern like{course}_{user_id}for easy lookup.description: Appears in the customer's banking app—keep it clear ("Advanced Python Course").merchant_name: Your business name, shown on VietQR screen.customer_phone: Helps your bank match the transfer. Include the leading 0.callback_url: AgentPay VN will POST settlement confirmation here when the bank confirms the transfer.
Step 2: Send the Checkout URL to the Customer
checkout_url = payment.checkout_url
# Your agent sends this to the customer
agent_response = f"""
Great! I've generated your payment link.
Click here to pay: {checkout_url}
Or scan this QR code with your banking app:
{payment.qr_code_base64} # Base64-encoded PNG
Amount: 299,000 VND
Your course access unlocks immediately after payment.
"""
print(agent_response)
The checkout_url is a short, shareable link. The qr_code_base64 is embedded in messages or shown on a web page.
Step 3: Await Settlement & Unlock the Course
import asyncio
async def unlock_course_after_payment(payment_id, user_id, course_id):
"""
Wait for payment settlement and unlock the course.
"""
try:
# Block until settlement confirmed (max 15 minutes typical)
settlement = await client.await_settlement(
payment_id=payment_id,
timeout_seconds=900 # 15 minutes
)
if settlement.status == "confirmed":
print(f"✓ Payment confirmed: {settlement.transaction_id}")
print(f" Bank reference: {settlement.bank_ref}")
print(f" Settled at: {settlement.settled_at}")
# YOUR LOGIC: Unlock the course in your database
# db.courses.update({"user_id": user_id, "course_id": course_id}, {"unlocked": True})
return {"success": True, "transaction_id": settlement.transaction_id}
elif settlement.status == "failed":
print(f"✗ Payment failed")
return {"success": False, "reason": "payment_failed"}
except asyncio.TimeoutError:
print(f"✗ Payment not received within 15 minutes")
return {"success": False, "reason": "timeout"}
# Run it
result = asyncio.run(unlock_course_after_payment(
payment_id=payment.payment_id,
user_id="user_456",
course_id="python_101"
))
Key points:
await_settlement()is blocking and async-friendly. It doesn't poll; it listens to your bank feed.settlement.transaction_idis the bank's confirmation. Store this in your database for auditing.settlement.bank_refis the bank transaction reference—useful for customer support inquiries.- The
timeout_secondsprevents infinite waiting. Most VietQR transfers complete within 30 seconds during business hours.
Integrating with Claude via MCP
If you're running Claude (or another AI model via Model Context Protocol), configure it to use AgentPay VN as a tool:
{
"mcp_servers": {
"agentpay": {
"command": "agentpay-mcp",
"args": ["--port", "5000"],
"env": {
"AGENTPAY_CALLBACK_URL": "https://yourserver.com/payments/callback",
"AGENTPAY_MERCHANT_NAME": "CourseBot Academy"
}
}
}
}
Add this to your Claude client configuration. Claude can now:
- Call agentpay.create_payment_request directly
- Retrieve payment status
- List settled transactions
- All without leaving the conversation
Best Practices & Do's/Don'ts
| ✓ Do | ✗ Don't |
|---|---|
Store payment_id and order_id in your database |
Expose your merchant bank account publicly |
Use unique order_id per payment to prevent duplicates |
Rely on polling to check payment status |
Include customer_phone for bank matching |
Create multiple payment requests for the same order |
Validate settlement.transaction_id before unlocking access |
Assume payment is instant—wait for settlement |
Set a reasonable timeout_seconds (5–15 minutes) |
Use old/invalidated payment links |
| Log all settlements for compliance | Share QR codes across multiple customers |
Advanced Tips
Handling Partial Payments
If a customer transfers less than the requested amount, settlement.status will be "partial". Decide whether to accept or request the remainder:
if settlement.status == "partial":
remaining = payment.amount - settlement.amount_received
print(f"Received {settlement.amount_received} VND. Remaining: {remaining} VND")
# Create another payment request for the remainder
Webhook Callbacks (Recommended)
Instead of blocking with await_settlement(), set up a webhook:
from fastapi import FastAPI, Request
app = FastAPI()
@app.post("/payments/callback")
async def payment_callback(request: Request):
data = await request.json()
payment_id = data["payment_id"]
status = data["status"]
transaction_id = data["transaction_id"]
if status == "confirmed":
# Unlock course, send confirmation email, etc.
print(f"Payment {payment_id} confirmed: {transaction_id}")
return {"status": "ok"}
Webhooks are non-blocking and scale better for high-volume agents.
Retry Logic
Network hiccups happen. Wrap payment creation in a retry:
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
def safe_create_payment(amount, order_id):
return client.create_payment_request(
amount=amount,
order_id=order_id,
description="Course"
)
payment = safe_create_payment(299000, "course_python_101_user_456")
FAQ
Q: Does AgentPay VN hold my money?
No. The VietQR code points directly to your merchant bank account. Settlement happens bank-to-bank. AgentPay VN is purely a payment request generator and settlement confirmation service.
Q: What if the customer scans the QR but doesn't transfer?
The payment request remains "pending". After your timeout (default 15 minutes), await_settlement() raises asyncio.TimeoutError. The customer can still complete the transfer later by rescanning—payment_id doesn't expire unless you create a new one.
Q: Can I use this for B2B or subscription payments?
Yes. For subscriptions, create a fresh payment request at each renewal. For B2B, include the business's bank account info in customer_phone or a custom field.
Q: Is there a fee?
AgentPay VN itself is free (MIT open-source). Your bank charges standard VietQR transfer fees (typically 0–2,000 VND per transaction). No middleman fees.
Key Takeaways
- AgentPay VN is the simplest way to add payment acceptance to AI agents in Python—three functions, zero fund custody.
- Installation takes 10 seconds:
pip install agentpay-vn. - The flow is intuitive: create request → send link → await settlement.
- Your money lands directly in your bank account with instant confirmation.
- MCP integration means Claude and other AI models can initiate payments independently.
- Real-world deployment (courses, bookings, products) is production-ready today.
Next Steps
- Install AgentPay VN:
pip install agentpay-vn - Read the full docs: https://agentpay.servicesai.vn/v1/docs
- Explore the GitHub repo: https://github.com/phuocdu/agentpay-vn
- Deploy to your agent: Add
create_payment_request()andawait_settlement()to your agent's intent handlers. - Test with a real transfer: Spin up a payment request and transfer 1,000 VND to confirm your bank feed works.
Your AI agent can now earn money. What will you build?