VietQR Payment Automation for AI Agents: Stripe Alternative
The Problem: Payment Bottlenecks in Vietnamese AI Workflows
Imagine you've built an AI chatbot for a Hanoi-based online course platform. It can onboard students, answer questions, and schedule sessions—but the moment someone wants to enroll, your agent hits a wall. Stripe? Requires complex webhook infrastructure, cross-border complexity, and fees that bite into already-thin margins for VND transactions. Your agent can't directly trigger a payment request without juggling API credentials, webhook listeners, and settlement delays.
Now multiply that friction across Vietnamese SaaS startups, micro-businesses, and autonomous systems. The gap between having an AI agent and monetizing it via local payment rails is real. That's where AgentPay VN enters the picture.
What Is AgentPay VN? The Short Version
AgentPay VN is an open-source Python SDK (MIT license) + MCP (Model Context Protocol) server that lets your AI agents collect VietQR payments directly from Vietnamese bank accounts. It's lightweight, bank-agnostic, and—critically—never holds money. The QR code points straight to the merchant's bank account. A bank feed confirms settlement. Three lines of code. Real payments.
- GitHub: https://github.com/phuocdu/agentpay-vn
- Docs: https://agentpay.servicesai.vn/v1/docs
- Install:
pip install agentpay-vn - MCP Server:
agentpay-mcp
Why VietQR? Why Now?
Vietnam's banking ecosystem has matured. VietQR (launched 2021) is now standard across 40+ banks and mobile wallets. It's the de facto way Vietnamese consumers and businesses transfer money. Unlike Stripe or PayPal, there's zero onboarding friction—if you have a Vietnamese bank account, you can accept payments immediately.
For AI agents, this unlocks a critical use case: autonomous payment collection without middleware complexity. Your Claude instance, your n8n workflow, your custom agent—any of them can now say, "Here's your checkout link," and genuinely settle funds.
Core Workflow: 3 Steps to Live Payments
Step 1: Create a Payment Request
Your agent initiates a payment by specifying amount, description, and merchant details. The SDK generates a unique request ID and prepares the settlement flow.
from agentpay_vn import create_payment_request
# Agent: "I need to collect 199,000 VND for a course enrollment."
request = create_payment_request(
amount=199000, # VND
description="Online Python Course - Month 1",
merchant_bank_account="1234567890", # Your bank account number
merchant_bank_code="MB", # VietQR bank code (e.g., MB, VCCB, TCB)
merchant_name="Tech Academy Vietnam",
order_id="student_alice_2024_001",
callback_url="https://your-api.example.com/payment-webhook"
)
print(f"Payment Request ID: {request['id']}")
print(f"Status: {request['status']}")
Line-by-line:
- amount: Payment in Vietnamese Dong (no decimals—VietQR is whole-number only).
- merchant_bank_account & merchant_bank_code: Where the money lands. Get these from your bank.
- order_id: Unique reference for your agent's ledger (e.g., "student_alice_2024_001").
- callback_url: Optional. Webhook your agent listens to when payment settles.
Step 2: Send the Checkout URL to the User
The request object contains a checkout_url—this is the VietQR link. Your agent forwards it to the customer.
checkout_url = request['checkout_url']
# Agent tells the customer:
print(f"Please complete payment here: {checkout_url}")
print(f"Or scan this QR: {request['qr_code_url']}")
The customer opens the link, selects their bank, and completes the transfer in their banking app. Simple. No redirects. No form-filling.
Step 3: Await Settlement Confirmation
Your agent polls or listens for settlement confirmation. The SDK provides a blocking wait function:
from agentpay_vn import await_settlement
import asyncio
async def process_enrollment(request_id):
# Agent waits for payment confirmation (timeout: 3600 seconds = 1 hour)
settlement = await_settlement(
request_id=request_id,
timeout_seconds=3600
)
if settlement['status'] == 'settled':
print(f"✅ Payment of {settlement['amount']} VND confirmed!")
print(f"Settlement time: {settlement['settled_at']}")
# Agent: enroll student, send confirmation email, etc.
return True
else:
print(f"❌ Payment failed or expired.")
return False
# Run it
if __name__ == "__main__":
asyncio.run(process_enrollment(request['id']))
Once settlement is confirmed, your agent proceeds: grant access, send confirmation, trigger downstream workflows.
Integration with AI Agents: MCP Server Setup
If you're using Claude (or another MCP-compatible agent), you can wire AgentPay VN as a tool the agent calls directly.
MCP Configuration (Claude Desktop)
Add to your claude_desktop_config.json:
{
"mcpServers": {
"agentpay": {
"command": "python",
"args": ["-m", "agentpay_mcp"],
"env": {
"AGENTPAY_MERCHANT_BANK": "MB",
"AGENTPAY_MERCHANT_ACCOUNT": "1234567890",
"AGENTPAY_MERCHANT_NAME": "Your Business Name",
"AGENTPAY_API_KEY": "your_api_key_here"
}
}
}
}
Now Claude has built-in actions:
- create_vietqr_payment – Initiate a payment request.
- check_settlement_status – Poll payment status.
- list_pending_payments – See open requests.
Your agent prompt becomes:
You are a course enrollment bot. When a student says "I want to buy the Python course,"
call create_vietqr_payment with amount=199000, description="Python Course", and the user's email.
Send the checkout_url to the student. Monitor with check_settlement_status every 10 seconds.
Once settled, enroll them and send a welcome email.
The agent handles the rest autonomously.
Real-World Walkthrough: AI-Powered Café Ordering
Let's say Lan runs a specialty coffee shop in District 1, Ho Chi Minh City. She wants to let customers pre-order via a Telegram bot powered by Claude.
Scenario:
1. Customer texts the bot: "I want 2 espressos and 1 cappuccino, pickup at 3 PM."
2. Bot calculates: 2 × 45,000 + 55,000 = 145,000 VND.
3. Bot calls create_payment_request(amount=145000, order_id="cafe_cust_001", ...).
4. Bot sends the checkout URL to the customer.
5. Customer pays via their bank app (takes ~30 seconds).
6. Bot detects settlement viaawait_settlement`.
7. Bot confirms the order and sends a kitchen ticket (via n8n integration).
8. Lan prepares the drinks, customer arrives and picks up.
Code skeleton:
from agentpay_vn import create_payment_request, await_settlement
def process_cafe_order(customer_id, items_total_vnd, order_details):
# Step 1: Create payment request
req = create_payment_request(
amount=items_total_vnd,
description=f"Café order: {order_details}",
order_id=f"cafe_{customer_id}_{int(time.time())}",
merchant_bank_account="0987654321",
merchant_bank_code="VCCB"
)
# Step 2: Send checkout URL to Telegram
send_telegram_message(customer_id, f"Pay here: {req['checkout_url']}")
# Step 3: Wait for settlement
settlement = await_settlement(req['id'], timeout_seconds=1800) # 30 min
if settlement['status'] == 'settled':
print(f"✅ Order confirmed. Sending to kitchen...")
trigger_kitchen_printer(order_details) # Your own integration
return True
else:
print(f"❌ Payment timeout. Order cancelled.")
send_telegram_message(customer_id, "Payment expired. Please try again.")
return False
The bot runs this whenever a customer commits to an order. No payment reconciliation. No settlement delay. Café operates on real-time payments.
Do's and Don'ts: Best Practices
| ✅ DO | ❌ DON'T |
|---|---|
Use unique order_id for every payment request (makes reconciliation easy). |
Hardcode merchant credentials in code—use environment variables. |
Set reasonable timeout_seconds (e.g., 1800 for retail, 86400 for invoices). |
Poll await_settlement in a tight loop—it's blocking; use async. |
| Log settlement confirmations for audit trails. | Assume payment settled without calling await_settlement. |
| Test with small amounts (1,000–5,000 VND) in dev before going live. | Forget to handle timeout scenarios—provide user feedback. |
| Use the MCP server for agent-native integrations (Claude, n8n, etc.). | Mix callback URLs and polling—pick one pattern and stick to it. |
Advanced Tips: Scaling and Reliability
Async Patterns for High Volume
If you're processing dozens of orders per minute, use asyncio and connection pools:
import asyncio
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=10)
async def batch_await_settlements(request_ids):
"""Wait for multiple payments in parallel."""
tasks = [
asyncio.to_thread(await_settlement, rid, timeout_seconds=1800)
for rid in request_ids
]
results = await asyncio.gather(*tasks, return_exceptions=True)
return results
# Usage:
results = asyncio.run(batch_await_settlements(['req_001', 'req_002', 'req_003']))
This waits for 3 payments concurrently, not sequentially—critical for busy platforms.
Webhook Listening (Optional but Recommended)
Instead of polling, listen for webhooks AgentPay VN sends when a payment settles:
from flask import Flask, request
app = Flask(__name__)
@app.route('/payment-webhook', methods=['POST'])
def payment_webhook():
payload = request.json
if payload['event'] == 'payment.settled':
order_id = payload['order_id']
amount = payload['amount']
settled_at = payload['settled_at']
# Enroll user, send email, etc.
print(f"✅ {amount} VND payment for {order_id} settled at {settled_at}")
return {"status": "received"}, 200
return {"status": "ignored"}, 200
Register this URL as callback_url in create_payment_request.
Multi-Bank Support
VietQR works across all major banks. The SDK auto-detects available bank codes for your region. To list them:
from agentpay_vn import list_supported_banks
banks = list_supported_banks()
# Output: ['MB', 'VCCB', 'TCB', 'VIB', 'BIDV', 'ACB', ...]
Let your user choose their preferred bank at checkout for a better UX.
FAQ
Q: Does AgentPay VN hold my money? No. The QR code points directly to your merchant bank account. AgentPay VN is a wrapper around VietQR standards—we never intermediate funds. Settlement happens bank-to-bank.
Q: What are the fees? AgentPay VN is open-source and free to use. Bank transfer fees are between you and your bank (typically 0.5–1% for merchants in Vietnam). No AgentPay markup.
Q: How fast is settlement? VietQR transfers settle within 1–2 hours on most banks (some same-day). Your agent can wait asynchronously during that time.
Q: Can I use it outside Vietnam? Not directly—VietQR is Vietnam-specific. But if your agent's users are in Vietnam, they can pay with any Vietnamese bank account or mobile wallet (Momo, ZaloPay, etc.) that supports VietQR.
Q: Is MCP integration required? No. You can use the Python SDK standalone. MCP is optional for Claude and compatible AI agents. If you're using a different agent framework, just import the SDK directly.
Key Takeaways
- Stripe alternative for Vietnam: VietQR is the native payment standard. No cross-border friction.
- 3-line payment flow: Create request → send URL → await settlement. That's it.
- No fund intermediation: Your agent's money goes straight to your bank account.
- Open-source + free: MIT license. Deploy anywhere. No vendor lock-in.
- AI-native: MCP integration means Claude and compatible agents call payments as first-class actions.
- Async-ready: Handle high-volume payments with Python's asyncio or webhook listeners.
- Proven UX: Customers know VietQR. No new apps. No new friction.
Next Steps
Ready to wire payments into your agent? Start here:
-
Install the SDK:
bash pip install agentpay-vn -
Read the full docs: https://agentpay.servicesai.vn/v1/docs
-
Clone the GitHub repo and run examples: https://github.com/phuocdu/agentpay-vn
-
Test locally with a small amount (1,000 VND) to confirm your bank setup.
-
Integrate the MCP server if you use Claude or compatible agents.
Your AI agents are now ready to collect real payments from real Vietnamese customers. No complexity. No middlemen. Just code and VietQR.
Questions or feedback? Open an issue on GitHub or check the docs. The AgentPay VN community is growing—join us.