Let Your AI Agent Accept VietQR Payments in Python
The Problem: Your AI Agent Can't Actually Get Paid
You've built an impressive AI agent—maybe it books appointments, sells digital courses, or processes café orders. It answers questions flawlessly, makes recommendations, and closes conversations brilliantly. But the moment a customer says "I want to buy," you hit a wall.
Your options today are bleak: - Option A: Redirect to an external payment gateway (kills the experience; customers drop off). - Option B: Integrate Stripe or similar (weeks of setup, monthly fees, complexity for Vietnam-specific needs). - Option C: Handle nothing and lose revenue entirely.
For Vietnamese merchants and AI developers, there's been no clean way to let agents accept domestic payments—until now. Enter AgentPay VN: an open-source Python SDK that lets your AI agent collect VietQR payments in three lines of code, with zero payment holding, zero account setup hassle, and full settlement directly to the merchant's bank.
What Is AgentPay VN?
AgentPay VN is a lightweight, MIT-licensed Python SDK paired with an MCP (Model Context Protocol) server that transforms your AI agent into a payment-collecting endpoint. Here's what makes it different:
Core mechanics: - No payment holding: The QR code points straight at your merchant's bank account. You own the money from second one. - Instant settlement confirmation: A bank feed signals when payment lands—no guessing, no delays. - Agent-native: Built for AI workflows. Claude, GPT, or your custom model can trigger payments without leaving the conversation. - MIT open-source: Full transparency; deploy anywhere. - VietQR standard: Works with every Vietnamese bank supporting VietQR.
Real flow in 3 steps:
1. create_payment_request() → generates a unique payment request
2. send_checkout_url() → shares the QR code with the customer
3. await_settlement() → confirms money arrived
That's it. No webhooks to debug, no OAuth flows, no mystery merchant accounts.
Why This Matters for AI Agents
Traditional payment gateways were built for websites and mobile apps, not agentic systems. They assume: - A human fills out a form. - A browser processes redirects. - A human confirms with their phone.
AI agents work differently. They: - Run in conversations (chat, API calls, async tasks). - Need to trigger payments within the dialogue without breaking context. - Must confirm settlement before delivering goods/services. - Operate 24/7 without human intervention.
AgentPay VN is designed for this. Your bot can say, "Here's your QR code—scan it to pay," watch for settlement in the background, and immediately deliver the digital product or confirm the booking—all within the same agent workflow.
Installation & Setup
Step 1: Install the SDK
pip install agentpay-vn
That's the only external dependency you need. No database, no config server required.
Step 2: Set Up Your Agent Environment
If you're using Claude or another LLM via the MCP server, install the MCP version:
pip install agentpay-mcp
Then add to your Claude configuration (e.g., claude_desktop_config.json):
{
"mcpServers": {
"agentpay": {
"command": "python",
"args": ["-m", "agentpay.mcp.server"]
}
}
}
This exposes create_payment_request, send_checkout_url, and await_settlement as tools Claude can call directly.
Step 3: Authenticate (Merchant Account)
You'll need a Vietnamese bank account to receive payments. AgentPay VN doesn't hold funds; it creates QR codes pointing at your account. During create_payment_request(), you supply:
- Your bank code (e.g., 970010 for Vietcombank)
- Your account number
- Transaction amount and description
No sign-ups, no waiting for approval—your bank's existing VietQR system handles the rest.
Core API: The 3-Line Flow
Creating a Payment Request
Here's a real-world example: a course-selling chatbot.
from agentpay_vn import PaymentRequest, VietQRPayment
# Initialize the payment processor
payment = VietQRPayment(
bank_code="970010", # Vietcombank
account_number="1234567890", # Your account
)
# Step 1: Create the request
request = payment.create_payment_request(
amount=299000, # 299,000 VND for a course
description="Python Mastery Course - License",
order_id="course_python_001_user123", # Unique per transaction
timeout_seconds=600, # 10 minutes to pay
)
print(f"Request ID: {request['id']}")
print(f"QR Data: {request['qr_data']}")
Line-by-line explanation:
- Lines 1-2: Import AgentPay VN classes.
- Lines 5-8: Initialize VietQRPayment with your bank credentials. This doesn't authenticate against a server—it's purely local config.
- Lines 11-16: Call create_payment_request(). You pass the amount in VND, a human-readable description, a unique order ID, and a timeout. Returns a dict with id (request tracking ID) and qr_data (the raw QR string to render).
- Lines 18-19: Log the essentials. request['qr_data'] is what you encode into a QR image or send as a string.
Sending the Checkout URL
Once you have the QR data, send it to the customer:
import qrcode
from io import BytesIO
# Step 2: Generate and send QR
qr = qrcode.QRCode(version=1, box_size=10)
qr.add_data(request['qr_data'])
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
# In a bot context, you'd send this image + message:
agent_message = f"""
Your course is ready! Scan this QR or send {request['amount']/1000:.0f}k VND to:
Account: {payment.account_number}
Bank: Vietcombank
Description: {request['description']}
Once paid, you'll get instant access.
"""
print(agent_message) # Send via chat/API
Key points:
- Generate a visual QR using the qr_data (shown here with qrcode library).
- Include fallback instructions (account number, bank, amount) in case scanning fails.
- The request['id'] is crucial for the next step—store it to track which customer paid.
Awaiting Settlement
This is where AgentPay VN shines:
import asyncio
# Step 3: Wait for payment
async def await_customer_payment(request_id, timeout=600):
"""
Block until payment confirmed or timeout.
Returns True if settled, False if timeout.
"""
result = await payment.await_settlement(
request_id=request_id,
timeout_seconds=timeout,
)
return result["settled"]
# Usage in an agent workflow:
async def sell_course(user_id, course_id):
# Create request
req = payment.create_payment_request(
amount=299000,
description=f"Course: {course_id}",
order_id=f"course_{course_id}_{user_id}",
timeout_seconds=600,
)
# Send QR to user (elided for brevity)
send_qr_to_user(req['qr_data'])
# Wait for settlement
if await await_customer_payment(req['id']):
# Payment confirmed! Deliver course.
grant_course_access(user_id, course_id)
return {"status": "success", "message": "Access granted!"}
else:
# Timeout—user didn't pay in time.
return {"status": "timeout", "message": "Payment window closed."}
# Run it
result = asyncio.run(sell_course("user123", "python_mastery"))
Breakdown:
- await_settlement(): Polls the merchant's bank feed (via VietQR) until it sees the matching payment, or the timeout expires. The bank feed is the source of truth—not AgentPay's database.
- Async/await pattern: Allows your agent to handle multiple concurrent payment requests without blocking.
- Return value: A dict with settled (boolean) indicating success. If False, the 10-minute window closed without payment.
Real-World Walkthrough: Café Ordering Bot
Imagine QuickCafé, a chatbot that takes orders and collects payment:
Conversation flow:
User: "I want 2 cappuccinos and a croissant."
Bot: "Great! That's 95,000 VND. Scan this QR to pay:
[QR IMAGE]
Or transfer to Vietcombank 1234567890."
[User scans and pays from their banking app]
Bot (after 2 seconds): "Payment confirmed! Your order is queued.
ETA: 15 minutes. We'll text you when it's ready."
Implementation:
class CafeOrderBot:
def __init__(self):
self.payment = VietQRPayment(
bank_code="970010",
account_number="0987654321",
)
self.orders = {} # Store active orders
async def process_order(self, user_id, items):
# Calculate total
total = sum(item['price'] for item in items)
# Create payment request
order_id = f"cafe_{user_id}_{int(time.time())}"
req = self.payment.create_payment_request(
amount=int(total * 1000), # Convert to VND
description=f"{len(items)} items - {user_id}",
order_id=order_id,
timeout_seconds=300, # 5 minutes to pay
)
# Send QR
self.send_message_with_qr(user_id, req['qr_data'])
# Wait for settlement
if await self.payment.await_settlement(req['id'], timeout_seconds=300):
self.orders[order_id] = {
"user_id": user_id,
"items": items,
"paid": True,
"status": "queued",
}
self.send_message(user_id, "Payment confirmed! Order queued.")
return True
else:
self.send_message(user_id, "Payment timeout. Order cancelled.")
return False
def send_message_with_qr(self, user_id, qr_data):
# Render QR and send via Telegram/SMS/App
qr = qrcode.QRCode()
qr.add_data(qr_data)
qr.make()
# ... send image to user
pass
def send_message(self, user_id, text):
# Send plain message
pass
# Usage
bot = CafeOrderBot()
orders = [
{"name": "Cappuccino", "price": 35000},
{"name": "Cappuccino", "price": 35000},
{"name": "Croissant", "price": 25000},
]
asyncio.run(bot.process_order("user_456", orders))
The bot creates a payment request, displays the QR, and waits. The moment the customer's bank confirms the transfer (usually within seconds), await_settlement() returns True, and the bot queues the order—all without human intervention.
Do's and Don'ts
| Do | Don't |
|---|---|
Do store request['id'] to track payments. |
Don't reuse the same order_id twice—each transaction needs a unique ID. |
Do set reasonable timeout_seconds (5–10 min). |
Don't assume settlement is instant; polling takes 1–3 seconds. |
Do use await_settlement() in async functions. |
Don't block the main thread; let other requests process in parallel. |
| Do include fallback payment info (account number) in QR descriptions. | Don't hardcode amounts in QR; fetch them dynamically. |
Do validate order_id uniqueness before creating requests. |
Don't store payment credentials in config files; use environment variables. |
Advanced Tips
1. Batch Payment Requests
For high-traffic scenarios (flash sales, group orders), create multiple requests in parallel:
import asyncio
async def create_batch_requests(num_requests):
tasks = [
payment.create_payment_request(
amount=100000,
description=f"Batch request {i}",
order_id=f"batch_order_{uuid.uuid4()}",
)
for i in range(num_requests)
]
return await asyncio.gather(*tasks)
2. Reconciliation Loop
Run a background task to reconcile unpaid orders:
async def reconciliation_loop(unpaid_orders, interval=30):
"""
Periodically check if old orders finally settled.
"""
while True:
for order_id, request_id in unpaid_orders.items():
result = await payment.await_settlement(
request_id=request_id,
timeout_seconds=5, # Quick check, don't block long
)
if result["settled"]:
unpaid_orders.pop(order_id)
log_settlement(order_id)
await asyncio.sleep(interval)
3. Rate Limiting
For production, add request throttling to avoid overwhelming the bank feed:
from asyncio import Semaphore
class ThrottledPayment:
def __init__(self, max_concurrent=10):
self.semaphore = Semaphore(max_concurrent)
self.payment = VietQRPayment(...)
async def throttled_await_settlement(self, request_id):
async with self.semaphore:
return await self.payment.await_settlement(request_id)
FAQ
Q: Does AgentPay VN hold my money? No. The QR code points directly at your merchant bank account. AgentPay only coordinates the request and listens to your bank's settlement feed. You own the money immediately.
Q: What if a customer pays but the agent doesn't detect it?
The bank confirms the transaction regardless. Your bank statement will show the incoming transfer. The await_settlement() call simply polls your bank feed for matching transactions. If it times out, you can manually reconcile or run the reconciliation loop (see Advanced Tips).
Q: Can I use this with GPT-4 / LangChain / other agents? Yes. The Python SDK works anywhere Python runs. The MCP server integrates with Claude and compatible LLM platforms. For other frameworks, import the SDK directly and call the functions in your agent's action handler.
Q: What if the customer's bank is slow?
VietQR settlements typically complete in 1–3 seconds for same-bank transfers, up to 30 seconds for inter-bank. Set timeout_seconds conservatively (5–10 minutes) to account for edge cases. The await_settlement() function will return False only if the full timeout elapses without a match.
Key Takeaways
- AgentPay VN is 3-line integration: Create request → send QR → await settlement. Zero complexity.
- No payment holding: Your merchant bank account is the source of truth. Settlement feeds confirm deposits.
- Built for agents: Async-first, designed for AI workflows without human intervention.
- MIT open-source: Full code transparency; deploy on your infrastructure.
- VietQR native: Works with every Vietnamese bank; no multi-currency or foreign payment hassles.
- Instant activation: No merchant onboarding, no waiting for approval. Use your existing bank account.
Whether you're selling courses, processing café orders, booking appointments, or running any transactional bot, AgentPay VN removes the payment barrier that keeps most AI agents from monetizing.
Get Started Now
-
Install the SDK:
bash pip install agentpay-vn -
Explore the docs: https://agentpay.servicesai.vn/v1/docs
-
Clone the repo: https://github.com/phuocdu/agentpay-vn
-
Build your payment-collecting agent and start accepting VietQR payments today.
The tools are here. Your agent is ready. Let's monetize it.