AI Chatbot Digital Product Sales Without Holding Funds
The Problem: AI Bots That Sell, But Can't Collect
Imagine you've built an impressive AI chatbot that recommends online courses, sells digital templates, or offers premium access to your SaaS platform. Your bot engages brilliantly, answers questions, and closes the sale. Then reality hits: how does it actually collect payment?
Traditional payment APIs force you into uncomfortable choices:
- Hold customer funds in a merchant account (compliance nightmares, regulatory friction, customer distrust).
- Redirect users away from the chat experience to a third-party checkout (conversion killer—studies show ~70% don't return).
- Store payment credentials yourself (PCI-DSS scope explosion, security liability).
- Build complex webhooks and settlement logic (weeks of engineering for something that should take hours).
In Vietnam especially, where VietQR has become the de facto standard for digital payments, this gap is acute. Your bot should work within the conversation, collect payment directly to your bank account, and never touch customer money.
AgentPay VN solves this in 3 lines of Python.
Why AgentPay VN Changes the Game
AgentPay VN is an open-source (MIT license) Python SDK + MCP server that bridges AI agents and instant bank transfers. Here's what makes it different:
Key Architecture: Zero-Custody Design
- QR points directly at your bank: When a customer scans the payment QR code, the transaction goes straight to your merchant bank account. AgentPay never sees or holds the money.
- Bank feed confirms settlement: A real-time feed from your bank confirms when payment lands, so your bot knows the sale is complete without polling.
- No payment gateway account needed: You don't sign up for a separate merchant processor. Your existing bank account is your payment processor.
- One-line install:
pip install agentpay-vnand you're ready to integrate.
This is fundamentally different from Stripe, PayPal, or Momo—which require you to trust a third party with customer funds and settlement. AgentPay is a bridge, not a vault.
Understanding the 3-Step Payment Flow
Before we code, let's map the flow your bot will follow:
Step 1: Create Payment Request Your bot generates a unique payment request with an amount, description, and internal order ID.
Step 2: Generate & Send Checkout URL AgentPay produces a VietQR code and checkout URL. Your bot sends this to the customer via chat, email, or webhook.
Step 3: Await Settlement Your bot polls the payment status (or listens to webhooks) until the bank confirms the transfer landed in your account.
Once confirmed, fulfill the digital product: unlock the course, send the download link, activate the license.
Building Your First AI Payment Bot in Python
Installation & Setup
Start with a clean Python 3.8+ environment:
pip install agentpay-vn
Next, configure your bank account details in a .env file or environment variables:
VIETQR_BANK_ACCOUNT_NO="1234567890" # Your account number
VIETQR_BANK_CODE="970400" # Your bank code (e.g., Vietcombank)
VIETQR_ACCOUNT_NAME="Your Name" # Account holder name
Complete Working Example: Course Sales Bot
Let's build a bot that sells a Python course for 99,000 VND:
from agentpay_vn import AgentPayClient, PaymentRequest
import time
# Initialize the AgentPay client
client = AgentPayClient(
bank_account="1234567890",
bank_code="970400",
account_name="Your Business Name"
)
def sell_course_to_customer(customer_id: str, customer_email: str):
"""
Orchestrates the full payment flow for a digital course sale.
"""
# Step 1: Create a payment request
# This generates a unique transaction ID and sets the amount
payment_request = PaymentRequest(
order_id=f"course_python_101_{customer_id}_{int(time.time())}",
amount_vnd=99000,
description="Python Advanced Course - Full Access",
customer_email=customer_email,
product_name="Python 101: Advanced Patterns"
)
# Step 2: Generate the checkout URL
# AgentPay creates a VietQR code and returns a shareable URL
checkout_response = client.create_payment_request(payment_request)
checkout_url = checkout_response["checkout_url"]
qr_code_url = checkout_response["qr_image_url"]
# Your bot sends this to the customer
print(f"📱 Please scan this QR code to pay:")
print(f"QR Image: {qr_code_url}")
print(f"Or open: {checkout_url}")
print(f"Amount: 99,000 VND")
# Step 3: Wait for payment confirmation
# Poll the settlement status until payment arrives
payment_confirmed = False
max_wait_seconds = 300 # 5 minute timeout
elapsed = 0
poll_interval = 5 # Check every 5 seconds
while not payment_confirmed and elapsed < max_wait_seconds:
settlement_status = client.await_settlement(
order_id=payment_request.order_id,
timeout_seconds=poll_interval
)
if settlement_status["status"] == "settled":
payment_confirmed = True
print(f"✅ Payment received! {settlement_status['amount_vnd']} VND confirmed.")
# Fulfill the digital product
send_course_access_link(
customer_email,
course_id="python_101_advanced"
)
return {"success": True, "order_id": payment_request.order_id}
elif settlement_status["status"] == "pending":
print(f"⏳ Waiting for payment... ({elapsed}s elapsed)")
else:
print(f"❌ Payment failed: {settlement_status.get('error', 'Unknown error')}")
return {"success": False, "reason": settlement_status.get('error')}
time.sleep(poll_interval)
elapsed += poll_interval
if not payment_confirmed:
print("⏱️ Payment timeout. Customer did not complete payment in time.")
return {"success": False, "reason": "timeout"}
def send_course_access_link(email: str, course_id: str):
"""
Fulfill the digital product (email, webhook, database update, etc.)
"""
access_token = generate_course_token(course_id, email)
send_email(
to=email,
subject="🎉 Welcome to Python 101: Advanced Patterns",
body=f"Access your course here: https://yourplatform.com/course/{course_id}?token={access_token}"
)
# Usage in your chatbot
if __name__ == "__main__":
result = sell_course_to_customer(
customer_id="user_12345",
customer_email="student@example.com"
)
print(result)
Line-by-line breakdown:
- Lines 7–11: Initialize the AgentPayClient with your bank details (set via environment variables for security).
- Lines 15–24: Create a PaymentRequest with a unique order ID, amount, and description. The order ID must be unique per transaction; adding a timestamp ensures this.
- Lines 27–32: Call
create_payment_request()to generate the VietQR checkout. The SDK returns both a QR image URL and a shareable checkout URL. - Lines 35–37: Send the checkout URL to the customer via chat/email/SMS.
- Lines 40–71: Poll the
await_settlement()endpoint every 5 seconds until the bank confirms payment landed. Once status is "settled", fulfill the product. - Lines 41–44: Set a 5-minute timeout; after that, assume the customer abandoned the payment.
- Lines 73–83:
send_course_access_link()is your fulfillment function—generate a token, send an email, update a database, etc.
Integrating with Claude via MCP
If you're using Claude or another AI agent via the Model Context Protocol (MCP), configure AgentPay as a tool server. This lets Claude call payment functions directly from conversation.
MCP Server Configuration (claude_desktop_config.json):
{
"mcpServers": {
"agentpay": {
"command": "python",
"args": ["-m", "agentpay_mcp.server"],
"env": {
"VIETQR_BANK_ACCOUNT_NO": "1234567890",
"VIETQR_BANK_CODE": "970400",
"VIETQR_ACCOUNT_NAME": "Your Business Name"
}
}
}
}
Install the MCP server:
pip install agentpay-vn[mcp]
Now, when you chat with Claude, you can ask: "I want to sell my e-book for 150,000 VND to user@example.com." Claude will:
- Call
agentpay.create_payment_request()with the amount and customer email. - Receive the checkout URL and QR code.
- Return the payment link to you in the chat.
- Optionally, poll for settlement and confirm when payment lands.
This makes selling from a chatbot truly hands-off.
Real-World Walkthrough: Digital Café Menu Bot
Let's apply this to a concrete scenario: a café offering digital gift cards via WhatsApp.
Scenario: ThanhCafe wants to sell digital gift cards (50k, 100k, 200k VND) via a WhatsApp bot.
Flow:
- Customer texts bot: "I'd like to buy a 100k gift card."
- Bot generates payment request with order_id
gift_card_100k_{timestamp}. - Bot sends back: "Scan this QR to pay 100,000 VND→" (with QR image).
- Customer scans with banking app, payment goes directly to ThanhCafe's bank account.
- Bot polls settlement status. When bank confirms the 100k arrived in ThanhCafe's account:
- Bot sends a unique gift card code to customer (e.g.,
GC-THANH-X7K9Q). - Bot sends the code to the café's POS system via webhook. - Customer redeems code at the cafe.
Code snippet for gift card scenario:
GIFT_CARD_DENOMINATIONS = {
"50k": 50000,
"100k": 100000,
"200k": 200000
}
def generate_gift_card_code():
import uuid
return f"GC-THANH-{str(uuid.uuid4())[:6].upper()}"
def handle_gift_card_purchase(amount_key: str, customer_phone: str):
amount_vnd = GIFT_CARD_DENOMINATIONS.get(amount_key, 100000)
payment_req = PaymentRequest(
order_id=f"giftcard_{amount_key}_{customer_phone}_{int(time.time())}",
amount_vnd=amount_vnd,
description=f"ThanhCafe Digital Gift Card - {amount_key}"
)
checkout = client.create_payment_request(payment_req)
# Send QR to WhatsApp
whatsapp_send_qr(customer_phone, checkout["qr_image_url"])
# Wait for settlement
if client.await_settlement(payment_req.order_id)["status"] == "settled":
code = generate_gift_card_code()
whatsapp_send_code(customer_phone, code)
# Also push to POS
notify_pos_system(code, amount_vnd)
Do's and Don'ts: Avoiding Common Pitfalls
| Do | Don't |
|---|---|
| ✅ Use unique order IDs (include timestamp or UUID) | ❌ Reuse the same order_id for multiple transactions |
| ✅ Poll settlement every 5–10 seconds | ❌ Poll every 1 second (wastes API quota and annoys your bank) |
| ✅ Set a payment timeout (e.g., 5–10 minutes) | ❌ Wait indefinitely; let transactions hang |
| ✅ Store order_id and customer email in your database | ❌ Lose track of who paid for what |
| ✅ Fulfill after settlement confirmation | ❌ Send course/key before payment confirmed |
| ✅ Log all payment events (for debugging & compliance) | ❌ Ignore failures; investigate later (chaos) |
| ✅ Use HTTPS for your fulfillment webhook | ❌ Send credentials or order IDs over HTTP |
| ✅ Test with small amounts (1,000–10,000 VND) first | ❌ Go live with large transactions without testing |
Advanced Tips: Scaling Your Payment Bot
1. Batch Processing for High Volume
If you're processing 100+ payments per day, avoid blocking waits:
import asyncio
from collections import deque
pending_orders = deque() # Track orders being processed
async def poll_all_settlements():
"""Background task that polls all pending orders."""
while True:
for order_id in list(pending_orders):
status = client.await_settlement(order_id, timeout_seconds=1)
if status["status"] == "settled":
on_payment_settled(order_id, status)
pending_orders.remove(order_id)
await asyncio.sleep(3) # Check every 3 seconds
2. Webhook Integration Instead of Polling
If AgentPay supports webhooks (check docs), register your fulfillment endpoint:
# In your Flask/FastAPI app
@app.post("/webhook/agentpay-settlement")
def on_settlement_webhook(request):
order_id = request.json["order_id"]
status = request.json["status"]
if status == "settled":
on_payment_settled(order_id, request.json)
return {"received": True}
This is faster and more reliable than polling.
3. Idempotency Keys for Duplicate Prevention
Network errors might cause you to create the same order twice. Use idempotency:
def create_payment_safe(customer_id: str, amount: int):
idempotency_key = f"{customer_id}_{amount}_{date.today()}"
# If this key was processed before, the server returns the cached result
return client.create_payment_request(
payment_request,
idempotency_key=idempotency_key
)
4. Retry Logic with Exponential Backoff
import random
def settle_with_retry(order_id: str, max_retries: int = 3):
for attempt in range(max_retries):
try:
status = client.await_settlement(order_id, timeout_seconds=5)
return status
except Exception as e:
if attempt < max_retries - 1:
wait_time = 2 ** attempt + random.uniform(0, 1)
print(f"Retry {attempt + 1} after {wait_time:.1f}s")
time.sleep(wait_time)
else:
raise
FAQ
Q: Does AgentPay charge fees?
A: AgentPay itself is free (MIT open-source). Your bank may charge standard transfer fees (typically 0–2,000 VND per transaction in Vietnam). No middleman fees apply.
Q: What if a customer pays but my server crashes before fulfillment?
A: Your bank will confirm the payment landed in your account. Query AgentPay with the order_id later (or check your bank statement) and fulfill retroactively. The payment is not lost; only your fulfillment step failed—which is separate and recoverable.
Q: Can I refund a customer?
A: AgentPay doesn't hold the money, so it can't refund. You would need to initiate a manual bank transfer back to the customer's account. Document the original payment order_id and transaction ID for reconciliation.
Q: Is AgentPay PCI-DSS compliant?
A: AgentPay never processes credit cards or sensitive payment details. It generates a VietQR code that customers pay via their banking app. No card data flows through AgentPay, so PCI scope is minimal. Your bot itself should still follow security best practices (HTTPS, secrets management, etc.).
Q: How fast is settlement confirmation?
A: In Vietnam, VietQR transfers are typically instant (seconds to minutes). AgentPay's bank feed confirms settlement as soon as your bank notifies it—usually within 1–5 minutes. This is much faster than traditional payment gateways (which settle in 1–3 business days).
Key Takeaways
✅ Zero-custody design: Your bank account is your payment processor. AgentPay never holds customer money.
✅ Three-line integration: create_payment_request → get QR URL → await_settlement. Real-world bots need ~50 lines (with error handling and fulfillment).
✅ Direct bank settlement: Customers pay via VietQR; the money lands in your bank immediately. No waiting for third-party processors to clear.
✅ MCP integration ready: Use AgentPay with Claude or any AI agent that supports Model Context Protocol.
✅ Ideal for digital products: Courses, templates, licenses, gift cards, e-books—anything digital that can be fulfilled programmatically.
✅ Open-source and MIT-licensed: Audit the code, modify for your needs, no vendor lock-in.
Ready to Launch?
Your AI agent is ready to collect payments. Here's how to start:
-
Install AgentPay VN:
bash pip install agentpay-vn -
Read the full documentation: 👉 https://agentpay.servicesai.vn/v1/docs
-
Explore the open-source code: 👉 https://github.com/phuocdu/agentpay-vn
-
Run the example above with a 50,000 VND test payment to your own account.
-
Deploy your bot and start selling digital products—immediately, with money flowing directly to your bank.
Your bot no longer just talks. Now it sells, collects, and settles. And it does it all without holding a single đồng.
Happy shipping! 🚀