AI Chatbot Payments Without Holding Funds: AgentPay VN

2026-08-15 · AgentPay VN

ai-agentspayment-integrationvietqrpython-sdkfintech

The Custody Problem Nobody Talks About

You've built an AI chatbot that sells digital products—online courses, design templates, software licenses. Your customers love it. But there's a silent risk lurking: where does the money live while it's being processed?

Most payment platforms require you to either: 1. Hold funds in an escrow account (compliance headache, regulatory scrutiny) 2. Use a third-party processor that takes 3–5% cuts and creates settlement delays 3. Build custom bank integrations (months of work, security nightmares)

None of these are good options for indie developers or small teams running AI agents in Vietnam or Southeast Asia.

AgentPay VN solves this with a radical simplification: your chatbot generates a VietQR code that points directly at your merchant bank account. Money never touches any intermediary.


Why Direct-to-Bank Payments Matter for AI Agents

When an AI agent collects payments, the architecture matters. Traditional setups add latency and friction:

AgentPay VN changes the equation:

Direct Settlement
Customer scans VietQR → money lands in your account within minutes → bank API confirms → agent logs completion.

This is especially powerful for: - SaaS trials & mini-payments ($1–$50 transactions where processor fees kill margins) - Course bundles sold by education chatbots - Freelancer rate cards issued by agent-powered services - Café/restaurant loyalty apps with AI personalization


How AgentPay VN Works: The Three-Line Mental Model

The entire flow lives in three operations:

1. create_payment_request()    → generates VietQR code + checkout URL
2. send checkout_url()         → agent delivers link to customer
3. await_settlement()          → bank feed confirms payment, agent resumes

No fund custody. No escrow. No third-party risk.


Installation & Setup

Step 1: Install the SDK

pip install agentpay-vn

This installs: - agentpay Python module (synchronous + async support) - agentpay-mcp command (for Claude/MCP server integration)

Step 2: Configure Your Bank Account

You'll need a VietQR-compatible Vietnamese bank account (most major banks: Vietcombank, Techcombank, MB Bank, etc.). AgentPay VN doesn't store credentials—it generates signed requests to your bank's API.

If you're integrating with Claude or another AI agent:

export AGENTPAY_BANK_ID="970418"  # Your bank code
export AGENTPAY_ACCOUNT="1234567890"  # Your account number
export AGENTPAY_ACCOUNT_NAME="Your Business Name"

Real Code: Building a Course-Selling Chatbot

Let's walk through a live example: an AI agent selling a $29 Python course.

The Payment Request Flow

from agentpay_vn import PaymentClient
import asyncio
from datetime import datetime, timedelta

# Initialize the payment client
client = PaymentClient(
    bank_id="970418",           # Vietcombank
    account_number="1234567890",
    account_name="Tech Courses VN"
)

# User wants to buy the Python course
async def handle_course_purchase(user_id: str, course_title: str, price: int):
    """
    user_id: "user_12345"
    course_title: "Advanced Python for AI"
    price: 290000 (in Vietnamese Dong)
    """

    # Step 1: Create a payment request
    # This generates a unique VietQR code + checkout URL
    payment = await client.create_payment_request(
        amount=price,
        description=f"Purchase: {course_title}",
        order_id=f"course_{user_id}_{int(datetime.now().timestamp())}",
        metadata={  # Store context about the purchase
            "user_id": user_id,
            "course_id": "py-ai-001",
            "course_title": course_title
        },
        expires_in=timedelta(hours=1)  # QR code valid for 1 hour
    )

    # payment object contains:
    # - payment.checkout_url: "https://checkout.agentpay.vn/pay/abc123xyz"
    # - payment.qr_code: Base64-encoded VietQR image
    # - payment.amount: 290000
    # - payment.order_id: "course_user_12345_1699123456"

    return payment

# Step 2: Send the checkout URL to the customer
async def send_checkout_to_customer(user_id: str, payment):
    """
    In a real chatbot, this is where you'd send the message to the user.
    Could be SMS, email, in-app notification, or Telegram.
    """
    message = f"""
    🎓 Your Python course is ready!

    Click to pay: {payment.checkout_url}

    Or scan this QR code:
    [VietQR Image]

    Payment amount: ₫290,000
    Valid for: 1 hour
    """

    # Send via your notification service
    # await telegram_bot.send_message(user_id, message)
    # await email_service.send(user_id, message)

    return message

# Step 3: Wait for settlement confirmation
async def grant_course_access_after_payment(user_id: str, order_id: str):
    """
    Poll the bank feed or use webhook (if configured) to confirm payment.
    Once confirmed, unlock the course.
    """

    # Wait for settlement (blocks until payment received or timeout)
    settlement = await client.await_settlement(
        order_id=order_id,
        timeout_seconds=3600  # Give customer 1 hour to pay
    )

    if settlement.status == "confirmed":
        # Bank confirmed the payment
        print(f"✅ Payment confirmed! Bank reference: {settlement.bank_reference}")

        # Now grant access to the course
        await grant_course_access(
            user_id=user_id,
            course_id="py-ai-001",
            download_url="https://courses.example.com/py-ai-001/download",
            access_expires=datetime.now() + timedelta(days=365)
        )

        # Send confirmation
        await notify_user_course_ready(user_id)

    else:
        # Payment not received
        print(f"❌ Payment not received. Status: {settlement.status}")
        await notify_user_payment_failed(user_id)

# Main agent flow
async def ai_agent_course_sales():
    user_id = "user_12345"
    course_title = "Advanced Python for AI"
    price = 290000  # VND

    # Create payment
    payment = await handle_course_purchase(user_id, course_title, price)

    # Notify customer
    await send_checkout_to_customer(user_id, payment)

    # Wait for payment
    await grant_course_access_after_payment(user_id, payment.order_id)

# Run it
if __name__ == "__main__":
    asyncio.run(ai_agent_course_sales())

Line-by-line breakdown:

  1. create_payment_request(): Generates a unique VietQR tied to your account. The QR code is stateless—it's just instructions to transfer money to you.
  2. metadata: Store context (user ID, course ID) so when the payment arrives, you know who it's from.
  3. expires_in: QR codes can expire. Useful to prevent accidental late payments.
  4. await_settlement(): Blocks until the bank confirms the transaction. This is where your agent "knows" the payment is real.
  5. Grant access: Once confirmed, you're free to unlock content, send download links, etc.

Integrating with Claude via MCP

If you're using Claude (or another LLM via Model Context Protocol), AgentPay VN exposes an MCP server:

# Start the MCP server
agentpay-mcp serve --bank-id 970418 --account 1234567890

Then configure Claude's claude_desktop_config.json:

{
  "mcpServers": {
    "agentpay": {
      "command": "agentpay-mcp",
      "args": ["serve"],
      "env": {
        "AGENTPAY_BANK_ID": "970418",
        "AGENTPAY_ACCOUNT": "1234567890",
        "AGENTPAY_ACCOUNT_NAME": "My Business"
      }
    }
  }
}

Now Claude can:

User: "Sell me your $29 course"

Claude (with AgentPay MCP):
  1. Calls agentpay.create_payment_request(amount=290000, ...)
  2. Gets checkout_url back
  3. Sends it to you
  4. Calls agentpay.await_settlement() to wait for confirmation
  5. Delivers your course once confirmed

This is a fully autonomous AI payment flow.


Real-World Walkthrough: Coffee Shop Loyalty AI

Imagine a café chain using an AI agent to manage loyalty rewards:

The Flow: 1. Customer orders coffee at register 2. Cashier asks: "Want loyalty points? Scan this QR or join via chatbot" 3. Customer chats with AI: "I want a 50-point card" 4. Agent creates payment request: 50,000 VND → 50 loyalty points 5. Customer scans QR, pays directly to café's bank 6. Bank confirms within 30 seconds 7. Agent logs points, sends digital card

Code snippet for this:

async def issue_loyalty_card(customer_phone: str, points: int, price_per_point: int = 1000):
    """
    Issue a loyalty card via payment.
    price_per_point = 1000 VND, so 50 points = 50,000 VND
    """
    total_price = points * price_per_point

    payment = await client.create_payment_request(
        amount=total_price,
        description=f"Loyalty card: {points} points",
        order_id=f"loyalty_{customer_phone}_{int(datetime.now().timestamp())}",
        metadata={"phone": customer_phone, "points": points}
    )

    # Send QR via SMS or chatbot
    await send_qr_to_phone(customer_phone, payment.qr_code)

    # Wait for payment
    settlement = await client.await_settlement(payment.order_id)

    if settlement.status == "confirmed":
        # Create the loyalty account
        await loyalty_database.create_card(
            phone=customer_phone,
            points=points,
            created_at=datetime.now()
        )
        await send_sms(customer_phone, f"✅ Loyalty card created! {points} points available.")

Do's and Don'ts

Do Don't
Use for one-time purchases ($1–$10,000 range) Hold customer funds between transactions
Store metadata (user ID, item ID) for reconciliation Ignore expired QR codes (implement timeouts)
Set short expiry windows (1–2 hours for best UX) Process payments without confirming via bank feed
Log every await_settlement() call for auditing Use this for gambling or regulated financial services
Test with small amounts first ($1 test transactions) Assume QR codes are secure without TLS (use HTTPS)
Use async/await for non-blocking agent flows Build your own bank integration (use the SDK!)

Advanced Tips

1. Batch Reconciliation

For high-volume agents, fetch all settled transactions periodically:

async def daily_reconciliation():
    # Get all payments settled today
    settled = await client.list_settlements(
        start_date=datetime.now().date(),
        status="confirmed"
    )

    for settlement in settled:
        print(f"Order {settlement.order_id}: {settlement.amount} VND")
        # Sync with your accounting system

2. Webhook Notifications

Instead of polling, register a webhook:

await client.register_webhook(
    url="https://your-api.com/agentpay/webhook",
    events=["payment.confirmed", "payment.expired"]
)

# Your server receives POST:
# {
#   "event": "payment.confirmed",
#   "order_id": "course_user_12345_1699123456",
#   "amount": 290000,
#   "bank_reference": "BK202401011234567"
# }

3. Retry Logic for Stalled Payments

async def payment_with_retries(order_id, max_retries=3):
    for attempt in range(max_retries):
        try:
            settlement = await client.await_settlement(order_id, timeout_seconds=300)
            return settlement
        except TimeoutError:
            if attempt < max_retries - 1:
                await asyncio.sleep(60)  # Wait 1 min, try again
            else:
                raise

FAQ

Q: What if a customer pays but the amount is wrong?

A: Bank feeds include the exact amount transferred. Your agent can validate settlement.amount against the expected price and either accept (if overpaid), refund (if underpaid), or reject. Refunds are issued back to the customer's bank account.

Q: Does AgentPay VN work with non-Vietnamese banks?

A: It requires a Vietnamese merchant bank account and VietQR compatibility. International transfers are beyond scope—the design assumes VND transactions within Vietnam. International merchants should use a VN bank partner or Wise API instead.

Q: How long does settlement confirmation take?

A: 30 seconds to 5 minutes typically. VietQR transfers are instant inter-bank; the delay is your agent polling the bank feed. Use webhooks for faster notification.

Q: Is this PCI DSS compliant?

A: Yes. AgentPay VN never handles card data. Money goes directly bank-to-bank via VietQR (QR code is just an instruction). You're not storing, processing, or transmitting card details.


Key Takeaways


Getting Started Now

Install AgentPay VN:

pip install agentpay-vn

Read full documentation:
https://agentpay.servicesai.vn/v1/docs

Browse source code:
https://github.com/phuocdu/agentpay-vn

Next steps: 1. Clone the repo and run the example chatbot 2. Generate a test VietQR code with your bank credentials 3. Build your first payment flow (you can test with small amounts) 4. Integrate into Claude or your LLM of choice via MCP

Your AI agent is now ready to collect payments without ever touching a customer's money. No escrow, no middleman, no excuses.

Happy selling. 🎉

Get started →

← All posts