AI Chatbot Payments: Sell Digital Products Without Holding Funds
The Silent Killer of AI Chatbot Commerce
Imagine you've just launched a ChatGPT-powered chatbot that sells online courses, design templates, or API credits. A customer arrives, loves your product, and is ready to pay—but then friction appears. Your bot needs to process payment, hold funds temporarily, reconcile bank transfers, and handle refunds. You're now operating a payment processor, not an AI service.
Worse: compliance headaches. Most jurisdictions require licenses to hold customer money. Your scrappy startup suddenly looks like it's breaking regulations.
This is where AgentPay VN changes the game. Instead of your bot holding funds, payments flow directly into your bank account via VietQR—Vietnam's instant bank transfer standard. Your AI agent orchestrates the sale, but the money never touches your infrastructure.
What Makes AgentPay VN Different?
Most payment SDKs force you into a custody model: customer pays → funds sit in your merchant account → you transfer to bank. AgentPay VN inverts this:
- Zero fund custody: QR codes point directly to your bank account.
- AI-native: Built for agents and chatbots via a Python SDK and Claude-compatible MCP server.
- Instant settlement: Bank feeds confirm payments in real time—your agent knows the moment money lands.
- Open-source (MIT): No vendor lock-in. Audit the code yourself.
- One-liner install:
pip install agentpay-vn. No complex onboarding.
The result: a 3-line workflow for your bot—create request, send checkout URL, await settlement. That's it.
The 3-Line Payment Flow
Before diving into code, here's the conceptual flow that makes AgentPay VN so elegant:
- create_payment_request – Your bot generates a payment request with amount, description, and merchant details.
- send checkout_url – Bot shares a VietQR checkout link with the customer (SMS, email, chat message, etc.).
- await_settlement – Bot monitors the bank feed; once it confirms payment landed in your account, bot fulfills the order (sends API key, course link, file download, etc.).
No intermediate wallets. No escrow accounts. No waiting 3–5 business days. Your bank confirms settlement in seconds to minutes.
Getting Started: Installation and Setup
Step 1: Install the SDK
pip install agentpay-vn
That's genuinely it. No API keys to juggle, no complex initialization—AgentPay VN auto-detects your environment and bank details from your bank's VietQR registry.
Step 2: Configure Your Bank Account
You'll need: - A Vietnamese bank account (VietQR-enabled; most major banks support this). - Your account number and bank code (e.g., VCB for Vietcombank).
AgentPay VN uses these to generate QR codes that customers scan to pay you directly.
Step 3: Set Your Webhook or Bank Feed Monitor
You can either:
- Run the MCP server (agentpay-mcp) and let Claude fetch settlement status on demand.
- Integrate a bank feed service (like your bank's API) to push notifications to your bot.
We'll cover both below.
Real-World Walkthrough: A Course-Selling Chatbot
Let's say you've built CourseBot, a chatbot that sells Python programming courses. A user types: "I want the advanced course."
The Code Flow
import asyncio
from agentpay_vn import PaymentRequest, SettlementMonitor
from datetime import datetime, timedelta
# Initialize payment system
payment_system = PaymentRequest(
merchant_id="your_bank_account",
merchant_bank="VCB", # Vietcombank
merchant_name="CourseBot"
)
async def sell_course(user_id: str, course_name: str, price_vnd: int):
"""
Full flow: create payment request → send to user → await settlement → deliver course
"""
# Step 1: Create payment request
# This generates a unique QR code for this transaction
payment_req = payment_system.create_payment_request(
amount_vnd=price_vnd,
description=f"Course: {course_name}",
order_id=f"{user_id}_{course_name}_{datetime.now().timestamp()}",
expiry_minutes=30 # QR expires in 30 minutes
)
# payment_req contains:
# - qr_code_url: URL to image of VietQR code
# - checkout_url: Direct link to pay (mobile-friendly)
# - transaction_id: Unique ID to track settlement
print(f"Payment created. Send this link to user: {payment_req.checkout_url}")
# In a real bot, you'd send: "Click here to pay: {checkout_url}"
# Step 2: Monitor for settlement
# Create a settlement monitor (polls bank feed every 5 seconds)
monitor = SettlementMonitor(
transaction_id=payment_req.transaction_id,
timeout_seconds=600 # Wait up to 10 minutes
)
# Step 3: Await settlement
# This blocks until payment confirmed OR timeout
settlement = await monitor.await_settlement()
if settlement.confirmed:
print(f"✓ Payment confirmed! {settlement.amount_vnd} VND received.")
# Deliver the course
course_link = deliver_course_to_user(user_id, course_name)
return {
"status": "success",
"message": f"Course link: {course_link}",
"transaction_id": settlement.transaction_id
}
else:
print(f"✗ Payment not confirmed within timeout.")
return {"status": "timeout", "message": "Please try again."}
# Run it
async def main():
result = await sell_course(
user_id="user_123",
course_name="Python Advanced",
price_vnd=299000
)
print(result)
asyncio.run(main())
Line-by-Line Breakdown
- PaymentRequest(): Initializes the payment engine with your bank details. Zero external API calls at this point—it's all local.
- create_payment_request(): Generates a VietQR code pointing to your bank account. Returns a
transaction_idyou'll use to track settlement. - SettlementMonitor(): Watches your bank feed for a matching deposit. In real deployments, this polls your bank's API or listens to webhook events.
- await_settlement(): Async-friendly—your bot can monitor multiple transactions in parallel without blocking.
Integrating with Claude via MCP Server
If your bot runs on Claude (via API), use the MCP (Model Context Protocol) server for seamless integration:
MCP Configuration (Claude Settings)
{
"mcpServers": {
"agentpay": {
"command": "agentpay-mcp",
"args": [
"--merchant-id", "your_bank_account",
"--merchant-bank", "VCB",
"--webhook-secret", "your_secret_key"
]
}
}
}
Once active, Claude can:
- Call create_payment_request(amount, description) → Get a checkout URL instantly.
- Call check_settlement_status(transaction_id) → Verify if payment landed.
- Call list_recent_settlements() → See all confirmed transactions today.
Example Claude prompt:
User: "I want the Figma template pack. How much?"
Claude (using MCP):
1. Calls create_payment_request(amount=199000, description="Figma template pack")
2. Receives checkout_url
3. Responds: "That's 199,000 VND. Pay here: [link]. Once confirmed, I'll send your templates."
4. Periodically checks settlement status
5. When confirmed, sends download link
The MCP server handles bank-feed polling in the background—Claude doesn't need to worry about async complexity.
Advanced Tips & Best Practices
Tip 1: Handle QR Code Expiry Gracefully
VietQR codes can expire (default 30 minutes). Regenerate if needed:
if payment_req.is_expired():
new_req = payment_system.create_payment_request(
amount_vnd=price_vnd,
description=f"Course: {course_name} (retry)",
order_id=f"{user_id}_{course_name}_{datetime.now().timestamp()}"
)
# Send new checkout URL
Tip 2: Add Idempotency Keys
Prevent duplicate charges if a user accidentally scans twice:
payment_req = payment_system.create_payment_request(
amount_vnd=299000,
description="Course",
order_id="user_123_course_v1", # Same order_id = same transaction
idempotency_key="user_123_action_timestamp" # Prevents double-processing
)
Tip 3: Batch Multiple Orders
If your bot sells bundles, create requests for each item and aggregate settlement:
orders = [
("Python Course", 199000),
("Design Template", 99000),
("API Credits", 50000)
]
transactions = []
for name, price in orders:
req = payment_system.create_payment_request(
amount_vnd=price,
description=name,
order_id=f"{user_id}_{name}_{now()}"
)
transactions.append(req)
# Send all checkout URLs together, monitor in parallel
settlements = await asyncio.gather(*[
SettlementMonitor(t.transaction_id).await_settlement()
for t in transactions
])
Tip 4: Retry Failed Settlement Checks
Network hiccups happen. Implement exponential backoff:
async def await_with_retry(transaction_id: str, max_retries=5):
retry_count = 0
while retry_count < max_retries:
try:
monitor = SettlementMonitor(transaction_id, timeout_seconds=120)
return await monitor.await_settlement()
except ConnectionError:
retry_count += 1
await asyncio.sleep(2 ** retry_count) # Exponential backoff
raise Exception(f"Failed to confirm settlement after {max_retries} retries")
Do's and Don'ts
| Do | Don't |
|---|---|
Use order_id to tie transactions to specific users/orders. |
Don't reuse transaction_id across multiple payments. |
Set reasonable expiry_minutes (15–60 based on use case). |
Don't set expiry_minutes < 5 (customer won't have time to pay). |
Store transaction_id in your database for audit trails. |
Don't rely solely on polling; use bank webhooks if available. |
| Test with small amounts (1,000–5,000 VND) first. | Don't skip timeout handling; always define max wait times. |
| Monitor settlement logs to catch edge cases. | Don't assume instant settlement (bank processing adds 10–30 sec delay). |
FAQ
Q: Does my bank account need special setup for VietQR?
A: Most major Vietnamese banks (VCB, TCB, MB, ACB, etc.) auto-enable VietQR. Check your bank's app—if you can generate a static QR code, you're set. AgentPay VN uses your existing account; no special merchant registration needed.
Q: What if a customer claims they paid but settlement didn't confirm?
A: Check your bank's transaction history first—payments sometimes take 30–60 seconds. If the bank confirms it landed but AgentPay VN didn't detect it, log the transaction_id and reach out to support. Keep records of the customer's proof (screenshot, etc.) for dispute resolution.
Q: Can I use AgentPay VN outside Vietnam?
A: The SDK is designed for Vietnamese banks and VietQR. If your customer is outside Vietnam but has a VietQR-enabled app (Vietcombank app, MB Bank, etc.), they can still pay. For non-Vietnamese customers, consider a multi-gateway approach: AgentPay VN for VN-based users, Stripe/PayPal for international.
Q: How do I handle refunds?
A: Refunds are manual—you initiate a bank transfer to the customer's account using your bank's app/API. AgentPay VN doesn't automate refunds (by design, since it doesn't hold funds). Log the refund reason and original transaction_id for your records.
Key Takeaways
- No fund custody: Money goes straight to your bank account. You're not a payment processor.
- 3-line flow: create → send → await. That's genuinely all your bot needs to do.
- AI-native: Python SDK + MCP server means your chatbot doesn't fight the framework.
- Compliance-friendly: You're not holding customer funds, so licensing is simpler.
- Open-source: MIT license. Deploy on your own servers, no vendor lock-in.
- Real-time settlement: Bank confirms deposits in 10–60 seconds. Deliver courses/files immediately.
Next Steps
Ready to monetize your AI agent?
- Install:
pip install agentpay-vn - Explore the docs: https://agentpay.servicesai.vn/v1/docs
- Clone examples: https://github.com/phuocdu/agentpay-vn
- Test with 1,000 VND to your own account—see how fast settlement happens.
- Ship it: Add payment requests to your chatbot and start selling.
Your bot shouldn't need a CFO. AgentPay VN keeps it simple.