AI Chatbot Payment Collection Without Holding Funds
The Problem: Payment Friction in AI-Driven Sales
Imagine you've built an AI chatbot that sells digital products—online courses, design templates, consulting hours. A customer asks to buy. Your chatbot processes the order, generates an invoice, and then... what? You send them a payment link to a payment gateway you don't fully trust, or worse, you ask them to wire funds to your personal account, hoping they follow through.
Better yet: you're now a payment intermediary. You're holding customer funds, managing refunds, dealing with chargebacks, and exposing yourself to regulatory headaches in Vietnam. The friction kills conversions. The compliance risk keeps you up at night.
This is where most AI payment integrations break down. They force you to choose between complexity (setting up merchant accounts, integrating Stripe/PayPal) or risk (holding money yourself).
What if there was a third way?
Introducing AgentPay VN: Direct Bank Payments for AI Agents
AgentPay VN is an open-source Python SDK and Model Context Protocol (MCP) server that lets your AI agents collect payments directly into your merchant's bank account—without ever touching the funds themselves.
Here's the core idea:
- Customer initiates purchase via your AI chatbot
- Agent creates a payment request linked to your VietQR merchant code
- Customer scans QR or clicks link → money goes straight to your bank
- Settlement confirmed via bank feed integration
- Agent fulfills order (sends download link, course access, etc.)
No escrow. No holding accounts. No regulatory grey zones. Just direct, traceable, instant bank transfers.
Let's build this.
Installation & Setup: 3 Minutes to Live Payments
Step 1: Install the SDK
pip install agentpay-vn
That's it. The package includes the core payment request engine and settlement verification tools.
Step 2: Set Up Your MCP Server (Optional, for Claude)
If you're using Claude or another MCP-compatible agent, expose AgentPay as a tool:
pip install agentpay-mcp
Then add to your Claude MCP config (~/.config/claude/resources.json or equivalent):
{
"resources": [
{
"type": "mcp",
"name": "agentpay",
"description": "Create and verify VietQR payment requests",
"url": "sse://localhost:3000/mcp",
"capabilities": [
"create_payment_request",
"await_settlement",
"list_transactions"
]
}
]
}
Start the MCP server:
agentpay-mcp --port 3000 --merchant-id YOUR_MERCHANT_ID --merchant-name "Your Store"
Your agent now has native payment capabilities.
The 3-Step Payment Flow Explained
AgentPay distills payment collection into three operations. Let's walk through each.
Step 1: Create a Payment Request
When a customer decides to buy, your agent creates a payment request. Here's the real code:
from agentpay_vn import PaymentClient
# Initialize the client with your merchant details
client = PaymentClient(
merchant_id="YOUR_MERCHANT_ID",
merchant_name="My Digital Store",
api_key="your_api_key_here"
)
# Create a payment request for a course purchase
payment_request = client.create_payment_request(
amount=500000, # 500,000 VND
description="Advanced Python Course - Full Access",
order_id="order_20240115_001",
customer_email="student@example.com",
customer_phone="0912345678",
metadata={
"product_type": "course",
"course_id": "python-advanced-001",
"access_duration_days": 365
}
)
print(f"QR Code URL: {payment_request.checkout_url}")
print(f"Request ID: {payment_request.id}")
print(f"Amount: {payment_request.amount} VND")
Line-by-line breakdown:
- merchant_id & merchant_name: Your VietQR merchant identity (provided by your bank)
- amount: Price in Vietnamese Dong; AgentPay handles no currency conversion
- description: What appears on the customer's bank statement
- order_id: Your internal tracking ID (must be unique per transaction)
- metadata: Custom fields your agent can reference later (e.g., course ID, subscription term)
- checkout_url: A shareable link the customer can click or a QR code they can scan
Step 2: Send the Checkout URL to Your Customer
Your agent now has a checkout URL. It can:
- Email the link:
"Click here to pay: {payment_request.checkout_url}" - Display a QR code in the chat: Generate the image from
checkout_url - Embed it in a web widget
The customer pays directly—their bank transfers money to your merchant account. AgentPay never sees the funds.
Step 3: Await Settlement & Fulfill
Once payment lands in your account, you fulfill. Here's how you verify:
import asyncio
from agentpay_vn import PaymentClient
async def fulfill_course_access(payment_request_id, customer_email):
client = PaymentClient(merchant_id="YOUR_MERCHANT_ID")
# Poll for settlement confirmation (bank feed integration)
settlement = await client.await_settlement(
payment_request_id=payment_request_id,
timeout_seconds=300 # Wait up to 5 minutes
)
if settlement.status == "SETTLED":
print(f"✓ Payment received: {settlement.amount} VND")
# Trigger fulfillment (your custom logic)
await send_course_access_link(customer_email)
await log_transaction(payment_request_id, "COMPLETED")
return {"status": "success", "message": "Course access granted!"}
else:
return {"status": "pending", "message": "Awaiting payment confirmation..."}
# Your agent calls this after sending checkout URL
await fulfill_course_access("payment_12345", "student@example.com")
What's happening:
- await_settlement() listens to your bank feed (via API integration)
- When funds appear in your account, it confirms the transaction
- Your agent immediately triggers fulfillment (no manual approval needed)
- The entire cycle—from purchase intent to course access—completes in seconds
Real-World Example: An AI Course-Selling Chatbot
Let's see AgentPay in action. You run a Python education startup with an AI tutor chatbot. A student messages: "I want to buy your advanced async course."
Here's what happens under the hood:
The Conversation
Student: "I want the advanced async course."
Agent: "Great! The course is 500,000 VND and includes 6 months of access. Let me set up payment for you."
(Agent calls create_payment_request)
Agent: "Here's your payment link: [QR code]. Scan with any banking app and confirm the transfer. I'll grant access as soon as it lands in our account."
Student: (Scans QR, pays via their bank app)
Agent: (Detects settlement via await_settlement)
Agent: "Payment confirmed! Here's your course login: [link]. Start learning anytime. Your access expires in 6 months."
The Code Stack
from agentpay_vn import PaymentClient
from datetime import datetime, timedelta
import uuid
class CourseBot:
def __init__(self, merchant_id, api_key):
self.client = PaymentClient(
merchant_id=merchant_id,
api_key=api_key
)
async def handle_purchase(self, student_email, course_id):
# Fetch course details
course = self.get_course(course_id) # Your DB query
# Create payment request
payment = self.client.create_payment_request(
amount=course['price'],
description=f"Purchase: {course['title']}",
order_id=f"order_{uuid.uuid4()}",
customer_email=student_email,
metadata={
"course_id": course_id,
"student_email": student_email,
"access_days": 180
}
)
# Send checkout to student
message = f"Pay here: {payment.checkout_url}"
await self.send_message(student_email, message)
# Wait for settlement
settlement = await self.client.await_settlement(
payment_request_id=payment.id,
timeout_seconds=600
)
if settlement.status == "SETTLED":
# Grant access
access_token = self.create_access_token(
student_email,
course_id,
days=180
)
await self.send_course_link(student_email, access_token)
return "Course access granted"
else:
return "Payment pending. Check your bank app."
No payment processor account. No holding funds. Just your bank account, your students' bank accounts, and a simple Python orchestration.
Advanced Tips: Production Hardening
1. Idempotency: Prevent Double Charges
Network hiccups can cause duplicate requests. Always use stable order_id values:
# BAD: Uses random UUID each time
order_id = str(uuid.uuid4())
# GOOD: Derives from customer + timestamp + product
order_id = f"course_{student_id}_{course_id}_{int(time.time())}"
If the same order ID is submitted twice, AgentPay reuses the existing payment request.
2. Timeout Handling
Bank feeds can lag 5–30 seconds. Don't hardcode short timeouts:
# Set timeout to business logic needs, not technical comfort
settlement = await client.await_settlement(
payment_request_id=payment.id,
timeout_seconds=60 # 1 minute is reasonable for most cases
)
# If timeout, user can retry later—no data loss
if settlement.status == "PENDING":
# Store payment ID in session, let user come back
session['pending_payment_id'] = payment.id
3. Metadata for Tracking
Use metadata to link payments back to your business logic:
payment_request = client.create_payment_request(
amount=amount,
description=description,
order_id=order_id,
metadata={
"internal_user_id": user_id,
"feature_flag": "early_bird_pricing",
"campaign": "email_august_2024",
"session_id": session.id
}
)
# Later, retrieve and analyze
transactions = client.list_transactions(
filters={"metadata.campaign": "email_august_2024"}
)
Do's & Don'ts
| Do | Don't |
|---|---|
Use unique order_id per transaction |
Reuse order IDs across different customers |
Store payment_request.id for settlement checks |
Lose track of the request ID |
| Set reasonable timeouts (30–120 seconds) | Hardcode 5-second timeouts |
| Use metadata for all contextual data | Rely on external logs to link payments |
| Test with test merchant ID first | Deploy to production immediately |
| Handle PENDING status gracefully | Assume failed payment = bad request |
| Monitor bank feed latency | Assume instant settlement |
FAQ
Q: Does AgentPay hold my money? No. The QR code points directly to your merchant's bank account (via VietQR infrastructure). Funds are transferred peer-to-peer between customer bank → your bank. AgentPay's role is orchestration and settlement confirmation only.
Q: What if a customer disputes the payment? Disputes are handled bank-to-bank (standard chargeback process). AgentPay provides the transaction history and metadata so you can defend your case. Your metadata should capture what was promised (course access, template pack, etc.).
Q: Can I use AgentPay with agents other than Claude? Yes. The SDK is agent-agnostic Python. You can use it with OpenAI's function calling, LangChain, AutoGen, or any Python-based agent framework. The MCP server is specifically for Claude and compatible tools.
Q: How do I test before going live?
AgentPay supports a test mode. Initialize with merchant_id="TEST_MERCHANT" and api_key="test_key". Test payments won't hit your real bank account.
Key Takeaways
- Direct transfers: VietQR routes payments straight to your bank account—you never hold funds
- 3-step flow:
create_payment_request→ send URL →await_settlement - AI-native: Built for agents; works with Claude via MCP, Python agents via SDK
- Zero intermediary risk: No escrow, no payment processor dependency, no fund-holding regulations
- Instant fulfillment: Agents can trigger order completion the moment settlement confirms
- Production-ready: Open-source, MIT license, bank-feed integration included
Getting Started Now
You're 3 minutes away from a working payment system:
pip install agentpay-vn
Then follow the quick-start guide to get your merchant ID from your bank, and deploy your first payment request.
For full API reference, examples, and MCP setup: - Docs: https://agentpay.servicesai.vn/v1/docs - GitHub: https://github.com/phuocdu/agentpay-vn - License: MIT (use freely, commercially and personally)
Your AI chatbot is now a sales engine. No payment intermediaries. No fund-holding risk. Just direct, transparent, agent-driven commerce.
Happy selling.