Let Your AI Agent Accept VietQR Payments in Python

2026-10-09 · AgentPay VN

pythonai-agentsvietqr-paymentsopen-sourcepayment-integration

The Problem: Your AI Agent Can't Get Paid

Imagine you've built an intelligent chatbot that teaches Vietnamese language lessons—it's genuinely useful, thousands of users love it, and they're ready to pay. But there's a catch: your agent has no way to collect money. You could bolt on Stripe or PayPal, but they add friction (foreign accounts, high fees), and worse, you're stuck managing fund transfers, KYC compliance, and customer support headaches that pull you away from building.

What if your AI agent could accept payments directly into your Vietnamese bank account—no middleman, no extra logins, just a QR code and instant settlement confirmation?

That's exactly what AgentPay VN solves. It's a lightweight, open-source Python SDK (MIT license) that lets AI agents collect VietQR payments in three lines of code. No money touches AgentPay's servers—payments flow straight to your bank, confirmed by a live feed.


Why VietQR Payments Matter for AI Agents

VietQR is Vietnam's unified QR payment standard, used by every major bank. For AI agent builders, it's a game-changer:

For context: a course-selling bot using AgentPay can process 50 payments/day and send instant "welcome" messages with zero manual intervention. A café ordering agent can collect table payments and trigger kitchen displays in real-time.


Installation & Quick Setup

Step 1: Install the SDK

pip install agentpay-vn

That's it. AgentPay VN has minimal dependencies (Python 3.8+, requests, pydantic).

Step 2: Get Your Merchant Credentials

  1. Visit AgentPay VN Docs.
  2. Register your merchant account (requires a Vietnamese bank account linked to VietQR).
  3. Receive your MERCHANT_ID and API_KEY.

Step 3: Set Environment Variables

export AGENTPAY_MERCHANT_ID="your_merchant_id"
export AGENTPAY_API_KEY="your_api_key"
export AGENTPAY_WEBHOOK_SECRET="your_webhook_secret"  # Optional, for real-time updates

The Three-Step Payment Flow

Every AgentPay payment follows the same pattern:

  1. Create a payment request – Your agent generates an order.
  2. Send the checkout URL – User receives a QR code.
  3. Await settlement – Agent confirms payment and delivers service.

Let's build this step-by-step.


Building Your First Payment Flow

Complete Python Example: Course Purchase Agent

import os
from agentpay_vn import AgentPayClient, PaymentRequest
import time

# Initialize the client (reads env vars automatically)
client = AgentPayClient()

# Step 1: User wants to buy a course
def create_course_order(student_name: str, course_id: str, price_vnd: int):
    """
    Create a payment request for a course purchase.
    price_vnd: Amount in Vietnamese Dong (e.g., 99000 for 99K VND)
    """
    payment_request = PaymentRequest(
        order_id=f"course_{course_id}_{int(time.time())}",
        description=f"Course enrollment for {student_name}",
        amount_vnd=price_vnd,
        metadata={
            "student": student_name,
            "course": course_id,
            "service": "education"
        }
    )

    # Create the request in AgentPay's system
    payment = client.create_payment_request(payment_request)

    # payment.checkout_url contains the QR code page
    print(f"Send this URL to {student_name}: {payment.checkout_url}")
    return payment

# Step 2: Wait for payment
def wait_for_payment(payment_id: str, timeout_seconds: int = 300):
    """
    Poll AgentPay for settlement confirmation.
    Blocks until payment succeeds or timeout.
    """
    start = time.time()

    while time.time() - start < timeout_seconds:
        status = client.get_payment_status(payment_id)

        if status.is_settled:
            print(f"✓ Payment settled! Amount: {status.amount_vnd} VND")
            print(f"  Bank reference: {status.bank_reference}")
            return status

        print(f"Waiting... (elapsed: {int(time.time() - start)}s)")
        time.sleep(2)  # Check every 2 seconds

    raise TimeoutError(f"Payment {payment_id} not settled within {timeout_seconds}s")

# Step 3: Orchestrate the flow
def enroll_student(student_name: str, course_id: str):
    """
    Full agent workflow: create order → send QR → deliver course access.
    """
    COURSE_PRICES = {
        "python_101": 199000,
        "django_pro": 499000,
        "ai_agents": 799000
    }

    price = COURSE_PRICES.get(course_id, 0)
    if not price:
        return {"error": "Course not found"}

    # Create payment
    payment = create_course_order(student_name, course_id, price)

    # Tell the agent to send the QR to the user
    print(f"🎓 Enrollment started for {student_name}")
    print(f"📱 They should scan: {payment.checkout_url}")

    # Wait for payment
    try:
        settled = wait_for_payment(payment.id)

        # ✓ Payment confirmed! Deliver the service
        return {
            "status": "enrolled",
            "student": student_name,
            "course": course_id,
            "access_link": f"https://yourplatform.com/course/{course_id}?token=abc123",
            "amount_paid": settled.amount_vnd
        }

    except TimeoutError:
        return {
            "status": "pending",
            "message": "Payment pending. Student can complete checkout anytime."
        }

# Test the flow
if __name__ == "__main__":
    result = enroll_student("Nguyen Van A", "python_101")
    print(result)

Line-by-line breakdown:


MCP Server Setup (For Claude / Anthropic)

If you're running AgentPay inside Claude or another MCP-enabled AI, use the agentpay-mcp server:

pip install agentpay-mcp
agentpay-mcp start --port 3001

Claude Configuration (claude_desktop_config.json)

{
  "mcpServers": {
    "agentpay": {
      "command": "agentpay-mcp",
      "args": ["start"],
      "env": {
        "AGENTPAY_MERCHANT_ID": "your_merchant_id",
        "AGENTPAY_API_KEY": "your_api_key"
      }
    }
  }
}

Now Claude can call AgentPay tools natively:

User: "I want to sell a 299K course"
Claude: [Calls agentpay:create_payment_request]
Claude: "Here's your checkout link: https://..."

Real-World Walkthrough: Café Ordering Bot

Let's say you run a small café in Ho Chi Minh City and want an AI bot to take table orders and collect payment instantly.

Scenario: A customer sits at Table 3, opens a QR code on the table, and chats with your bot.

from agentpay_vn import AgentPayClient

client = AgentPayClient()

def cafe_order_flow():
    # User selects: Cà phê đen 25K + Bánh mì 35K = 60K total
    order = {
        "table": 3,
        "items": [("Cà phê đen", 25000), ("Bánh mì", 35000)],
        "total": 60000
    }

    # Create payment for this table
    payment = client.create_payment_request({
        "order_id": f"table_3_{int(time.time())}",
        "description": "Café order - Table 3",
        "amount_vnd": order["total"],
        "metadata": {"table": 3, "items": len(order["items"])}
    })

    # Bot displays QR in chat
    print(f"Scan to pay 60,000 VND: {payment.checkout_url}")

    # Poll for settlement
    status = client.get_payment_status(payment.id)

    if status.is_settled:
        # ✓ Trigger kitchen display system
        print("Kitchen: Prepare Table 3 order!")
        # Send SMS: "Payment confirmed. Order ready in 10 mins."  
        return {"paid": True, "kitchen_triggered": True}

Result: From order to payment to kitchen in ~5 seconds. No cash handling, no manual entry, instant audit trail.


Advanced Tips & Best Practices

Handling Timeouts & Retries

import asyncio
from tenacity import retry, stop_after_attempt, wait_exponential

@retry(stop=stop_after_attempt(5), wait=wait_exponential(multiplier=1, min=2, max=10))
async def robust_await_settlement(payment_id: str):
    """Retry with exponential backoff if network fails."""
    return await client.get_payment_status(payment_id)

Webhooks for Real-Time Updates

Instead of polling, register a webhook:

client.register_webhook(
    url="https://yourserver.com/agentpay/webhook",
    events=["payment.settled"]
)

# Your endpoint receives: {"payment_id": "...", "amount_vnd": 99000, "settled_at": "..."}

This is 10x faster than polling and handles 100+ concurrent orders effortlessly.

Idempotency Keys

Always include a unique key to avoid duplicate charges:

payment = client.create_payment_request(
    payment_request,
    idempotency_key=f"order_{order_id}_{user_id}"  # Won't create twice if retried
)

Do's & Don'ts

✓ Do ✗ Don't
Use webhook confirmation for speed; poll only for fallback. Poll every 100ms; it wastes bandwidth. Poll every 2–5s.
Store bank_reference for reconciliation & audits. Assume payment succeeded without checking is_settled.
Use unique order_id per request (timestamp + UUID). Reuse order IDs; AgentPay will reject or confuse orders.
Set timeout based on user patience (5–10 min for e-commerce). Leave polling indefinitely; gracefully fail after 5 min.
Test with 1,000 VND first; AgentPay sandbox is free. Go live without testing; test thoroughly.

FAQ

Q: Does AgentPay hold my money?

No. Payment goes straight to your bank account registered with VietQR. AgentPay only confirms settlement via bank feed; it never holds funds.

Q: What's the settlement time?

Typically 2–10 seconds after the user completes payment in their banking app. AgentPay confirms it immediately via live bank feed.

Q: Can I use this internationally?

Currently, AgentPay VN is designed for Vietnam-based merchants with Vietnamese bank accounts. International support is on the roadmap.

Q: How much does it cost?

AgentPay charges a small per-transaction fee (check docs for current rates). No monthly fee, no setup cost. MIT license = free to use and modify.


Key Takeaways


Get Started Now

Installation:

pip install agentpay-vn

Documentation & Examples: - 📖 AgentPay VN Docs - 🔧 GitHub Repository

Next Steps: 1. Install the SDK. 2. Get your merchant credentials. 3. Run the course enrollment example above. 4. Deploy to production and start collecting payments.

Your AI agent is ready to get paid. Build something great.

Get started →

← All posts