Sell Digital Products from AI Chatbots Without Holding Funds
The Problem: Why Most AI Commerce Tools Force You to Hold Customer Money
You've built an AI chatbot that sells digital products—online courses, ebooks, design templates, or software licenses. Your customers are ready to pay. But when you look at payment integrations, every solution seems to push you toward the same uncomfortable reality: you become a money custodian.
You hold customer funds in a third-party account. You manage refunds manually. You juggle settlement timelines that span days. You become liable for fraud disputes. Regulators start asking uncomfortable questions about financial compliance. And worst of all, you're sitting on other people's money—legally and ethically risky territory for a solo developer or small team.
This friction exists because traditional payment gateways were built for marketplaces (Shopify, Stripe Connect, etc.), not for autonomous AI agents that need to collect money and immediately fulfill digital goods.
AgentPay VN solves this differently.
What AgentPay VN Does (And Doesn't)
AgentPay VN is a lightweight, open-source Python SDK (MIT licensed) plus an MCP server that lets your AI agents collect VietQR payments without holding a single dong. Here's the critical difference:
- Traditional payment gateways: Customer → Your merchant account → Settlement → Your bank (3–5 days later)
- AgentPay VN: Customer → Your merchant's bank account directly via QR (instant)
The QR code points straight at your actual bank account. No middleman account. No fund holding. A bank feed confirms when the customer's payment lands, and your bot immediately fulfills the order.
This isn't magic—it's pragmatic. Vietnam's VietQR system is designed exactly for this: peer-to-peer QR payments that settle in seconds.
Why This Matters for AI Chatbots
AI agents operate differently from traditional web stores. They need to:
- Make real-time decisions based on payment status (did the customer actually pay?)
- Execute immediately (generate the download link, unlock the course, send the API key)
- Avoid complexity (less code = fewer bugs in production)
- Scale without friction (no financial account management overhead)
With AgentPay VN, your agent can create a payment request, send the checkout URL to the customer, wait for settlement confirmation, and unlock the digital product—all in one conversational flow. No webhooks to debug. No reconciliation sheets. No regulatory headaches.
Getting Started: Installation and Setup
Step 1: Install the SDK
pip install agentpay-vn
That's it. The SDK is lightweight (~15 KB) with minimal dependencies.
Step 2: Configure Your Bank Details
You'll need: - Your bank account number - Your bank name (e.g., "VCB", "TCB", "MB") - Your full name (account holder) - Optional: A description for your merchant (e.g., "Alice's AI Course Bot")
Store these in environment variables or a config file. Never hardcode secrets in your agent code.
Step 3: Integrate with Your AI Agent
Here's a minimal example using the SDK directly:
from agentpay_vn import PaymentRequest, SettlementWatcher
import os
import asyncio
# Initialize with your bank details
bank_account = os.getenv("BANK_ACCOUNT_NUMBER")
bank_name = os.getenv("BANK_NAME") # e.g., "VCB"
account_holder = os.getenv("ACCOUNT_HOLDER")
# Step 1: Create a payment request for a digital product
async def sell_digital_product(customer_id: str, product_id: str, price_vnd: int):
# Generate a unique order reference
order_ref = f"order_{customer_id}_{product_id}_{int(time.time())}"
# Create the payment request
payment = PaymentRequest(
amount=price_vnd,
order_id=order_ref,
description=f"Digital Product {product_id}",
customer_id=customer_id,
bank_account=bank_account,
bank_name=bank_name,
account_holder=account_holder
)
# Step 2: Get the VietQR checkout URL
checkout_url = payment.generate_qr_url()
print(f"Send this to customer: {checkout_url}")
# In a chatbot, you'd send this via message: "Scan this QR code to pay."
# Step 3: Wait for settlement confirmation
watcher = SettlementWatcher(bank_account=bank_account)
# Poll for settlement (in production, use bank webhooks if available)
settled = await watcher.await_settlement(
order_id=order_ref,
expected_amount=price_vnd,
timeout_seconds=300 # 5 minutes
)
if settled:
print(f"✓ Payment confirmed! Unlocking {product_id}...")
# Fulfill the order: generate download link, unlock course access, etc.
await unlock_digital_product(customer_id, product_id)
return {"status": "success", "download_link": generate_download_link(product_id)}
else:
print("✗ Payment timeout.")
return {"status": "timeout", "message": "Please try again."}
# Example: Selling a $5 USD (~125,000 VND) course
asyncio.run(sell_digital_product(
customer_id="user_12345",
product_id="course_python_101",
price_vnd=125000
))
Line-by-line breakdown:
- Lines 8–12: Load bank details from environment (secure).
- Line 19: Create a unique
order_refso you can track this specific transaction. - Lines 22–29: Instantiate a
PaymentRequestwith the customer's payment amount and your merchant details. - Line 32: Generate the VietQR checkout URL (this is what the customer scans).
- Lines 37–38: Initialize a
SettlementWatcherto monitor your bank account for incoming payments. - Lines 40–46: Await settlement confirmation. The watcher polls your bank feed (or webhooks) and returns
Truewhen the customer's payment lands. - Lines 48–52: Once settled, unlock the digital product immediately (no delays).
Integrating with Claude via MCP
If you're building a Claude-powered agent, use the AgentPay VN MCP server to expose payment functions as tools.
MCP Configuration
Add this to your Claude MCP client config (e.g., claude_desktop_config.json):
{
"mcpServers": {
"agentpay-vn": {
"command": "agentpay-mcp",
"env": {
"BANK_ACCOUNT_NUMBER": "0123456789",
"BANK_NAME": "VCB",
"ACCOUNT_HOLDER": "Nguyen Van A",
"BANK_FEED_API_KEY": "your_bank_api_key_here"
}
}
}
}
Now Claude has access to three native tools:
create_payment_request— Generates a payment request object with QR URL.send_checkout_url— Sends the QR to the customer (via message, email, SMS).await_settlement— Polls for payment confirmation; returns when funds arrive.
Claude will automatically call these in sequence when a user asks to buy a product.
Real-World Walkthrough: An AI Course Sales Bot
Imagine you're selling a Python programming course for 299,000 VND (~$12 USD). Here's the conversation flow:
Customer: "I want to buy your Python Basics course."
Claude (Agent):
1. Calls create_payment_request(amount=299000, order_id="order_user123_course_python_001", description="Python Basics Course").
2. Receives a QR URL and calls send_checkout_url(url) to display it in the chat.
3. Tells the customer: "Scan this QR code with your bank app to pay 299,000 VND."
Customer: [Scans QR, transfers 299,000 VND from their bank account directly to yours in ~10 seconds]
Claude (Agent):
4. Calls await_settlement(order_id, expected_amount=299000, timeout=300).
5. Bank feed confirms the transfer landed in your account.
6. Calls an internal function: generate_course_access_token(customer_id) and send_download_link().
7. Tells the customer: "Payment received! Here's your course link: [link]. Access expires in 30 days."
Total time: ~15 seconds from QR scan to unlocked course. Your liability: Zero. Money went straight to your bank account.
Advanced Tips: Making It Production-Ready
1. Use Bank Webhooks Instead of Polling
Instead of await_settlement() polling every 2 seconds, ask your bank (VCB, TCB, etc.) if they offer webhooks for incoming transfers. AgentPay VN supports webhook handlers:
from agentpay_vn import WebhookHandler
handler = WebhookHandler(secret=os.getenv("BANK_WEBHOOK_SECRET"))
@handler.on_settlement
async def handle_payment_received(order_id: str, amount: int):
print(f"Payment received for {order_id}!")
await unlock_digital_product_by_order_id(order_id)
# No polling needed—this fires the instant money lands.
# In your FastAPI/Flask app:
app.post("/webhooks/agentpay")
async def webhook_endpoint(request):
await handler.process(request.json)
return {"status": "ok"}
2. Prevent Double-Spending
Always store the settlement confirmation in your database:
if settled:
# Check if already fulfilled
if not db.orders.find_one({"order_id": order_ref, "fulfilled": True}):
db.orders.insert_one({
"order_id": order_ref,
"customer_id": customer_id,
"amount": price_vnd,
"fulfilled": True,
"fulfilled_at": datetime.utcnow()
})
await unlock_digital_product(customer_id, product_id)
3. Handle Partial or Incorrect Payments
Sometimes a customer pays slightly less (bank fee) or the wrong amount. Decide your policy:
expected = 100000
actual = await watcher.get_received_amount(order_id)
if actual >= expected * 0.98: # Allow 2% variance for bank fees
await unlock_digital_product()
else:
await request_correction_from_customer()
4. Add Idempotency Keys
If your agent retries a request, use idempotency keys to prevent duplicate payments:
payment = PaymentRequest(
amount=price_vnd,
order_id=order_ref,
idempotency_key=f"{customer_id}_{product_id}" # Same key = same request
)
Do's and Don'ts
| ✅ Do | ❌ Don't |
|---|---|
Store bank details in environment variables (e.g., .env, AWS Secrets Manager) |
Hardcode bank account numbers in your source code |
Use unique order IDs (order_user123_prod456_timestamp) |
Reuse order IDs across different transactions |
| Implement idempotency keys for payment requests | Assume a payment request succeeded without confirmation |
| Log settlement events to your database | Rely only on in-memory state for payment confirmation |
| Set a reasonable timeout (5–10 minutes) for settlement waits | Wait indefinitely for a payment that may never arrive |
| Test with small amounts first (10,000 VND) | Go live with 10 million VND per transaction immediately |
FAQ
Q: Does AgentPay VN hold my money? No. The VietQR points directly at your bank account. Money lands in your account within seconds. AgentPay VN just confirms settlement; it never touches the funds.
Q: What if a customer disputes the charge? Disputes go through your bank, just like any normal transfer. You have transaction records (order ID, timestamp, amount) to defend yourself. This is actually simpler than marketplace payment disputes because it's a straightforward bank transfer.
Q: Can I refund a customer? Yes, but it's a manual process: you initiate a transfer back to their bank account. AgentPay VN doesn't automate refunds (since it's not holding the money). Consider this when setting your refund policy—you might want stricter no-refund terms for digital products.
Q: Which Vietnamese banks are supported? VietQR works with all major Vietnamese banks: VCB, TCB, MB, ACB, Vietinbank, etc. Check the full list at agentpay.servicesai.vn/v1/docs.
Key Takeaways
- AgentPay VN lets AI agents sell digital products without holding customer funds—money goes straight to your bank account.
- Three-line integration:
create_payment_request()→send_checkout_url()→await_settlement(). - VietQR is instant: Customers scan, pay, and you unlock the product in under 30 seconds.
- Lower compliance burden: No marketplace regulations, no fund custody liability—just regular bank transfers.
- Works with Claude and other AI agents via the MCP server integration.
- Production tips: Use bank webhooks for real-time confirmation, implement idempotency, store settlement records, and handle edge cases (partial payments, disputes).
Getting Started Today
You're three commands away from accepting AI-powered digital product payments:
pip install agentpay-vn
export BANK_ACCOUNT_NUMBER="your_account"
export BANK_NAME="VCB"
Then integrate the payment flow into your chatbot. Full documentation, examples, and the open-source SDK are available at:
📦 Install: pip install agentpay-vn
📚 Docs: https://agentpay.servicesai.vn/v1/docs
🔧 GitHub: https://github.com/phuocdu/agentpay-vn
Start selling today—no fund holding, no middleman, just you and your customers.