AI Agents Accept VietQR Payments in Python – Tutorial

2026-09-21 · AgentPay VN

pythonai-agentsvietqrpaymentsmcp-server

The Problem: AI Agents That Talk but Never Collect

You've built an impressive AI agent—maybe it tutors students, sells digital products, or books services. It converses naturally, understands context, and delivers real value. But when it comes time to accept payment, you hit a wall.

Traditional payment gateways expect humans clicking buttons on websites. They weren't designed for agents autonomously managing transactions. Your agent can't easily:

You're left either manually processing payments or using clunky workarounds that break the agent's autonomy. This is where AgentPay VN changes the game.

What is AgentPay VN?

AgentPay VN is an open-source (MIT license) Python SDK paired with an MCP server that lets AI agents collect Vietnamese VietQR payments directly. Here's what makes it different:

No money custody – The QR code points straight to your merchant bank account. AgentPay VN never touches funds; it's a coordination layer, not a payment processor.

Bank feed integration – Settlement confirmation comes from your bank's transaction history, not a third-party webhook that might fail.

Agent-native – Designed from day one for AI workflows. Three-line payment flow: create_payment_request() → send URL → await_settlement().

Open source – Full transparency, MIT license, run it yourself: github.com/phuocdu/agentpay-vn

Installation & First Steps

Install the SDK

pip install agentpay-vn

That's it. No API keys to hunt down, no rate limits to negotiate. You're ready to start building.

Optional: Run the MCP Server

If you're using Claude or another MCP-compatible AI agent, install the MCP server:

pip install agentpay-mcp
agentpay-mcp

This registers AgentPay as a tool your AI agent can call directly.

The Three-Step Payment Flow

Every transaction with AgentPay VN follows a simple, predictable pattern:

1. Create a Payment Request

You specify what you're selling: amount, description, and who's paying. AgentPay VN generates a unique request ID and returns a checkout URL.

2. Send the Checkout URL to the User

Your agent shares the URL with the customer (via chat, email, SMS—whatever channel fits your agent). The user scans the VietQR code or clicks the link, and their bank app opens.

3. Await Settlement

Your agent waits for confirmation from your bank feed that the transaction arrived. No polling external APIs; just a clean settlement event.

Code Example: Building a Course-Sale Bot

Let's build a real scenario: an AI agent selling online courses. A student asks about purchasing a Python course; the agent creates a payment request and awaits confirmation.

from agentpay_vn import PaymentClient
import asyncio

# Initialize the client (uses your bank account details)
client = PaymentClient(
    merchant_id="your_merchant_id",
    bank_code="VCB",  # Your bank code (VCB, ACB, etc.)
    account_number="1234567890",
)

async def sell_course_to_student(student_name: str, course_id: str, price: int):
    """
    Student asks to buy a course. Agent creates payment request,
    sends checkout URL, waits for settlement.
    """

    # Step 1: Create a payment request
    # price is in VND (Vietnamese Dong)
    payment_request = await client.create_payment_request(
        amount=price,
        description=f"Python Mastery Course for {student_name}",
        metadata={"course_id": course_id, "student": student_name},
        expire_in_minutes=30  # QR expires in 30 minutes
    )

    # payment_request contains:
    # - request_id: unique identifier
    # - checkout_url: customer scans or clicks this
    # - qr_code_data: raw VietQR data if you want to render your own QR

    print(f"📱 Payment link: {payment_request.checkout_url}")
    print(f"⏰ Expires: 30 minutes")

    # Step 2: Agent tells student where to pay
    # (In a real agent, this would be a chat message)
    agent_response = f"""
    Great! I've created your course access. 
    Scan this VietQR code or click here to pay {price:,} VND:
    {payment_request.checkout_url}
    """

    # Step 3: Wait for settlement
    # This is non-blocking; your agent can chat while waiting
    settlement = await client.await_settlement(
        request_id=payment_request.request_id,
        timeout_seconds=600  # Wait up to 10 minutes
    )

    if settlement:
        print(f"✅ Payment received! Transaction ID: {settlement.transaction_id}")
        print(f"💰 Amount: {settlement.amount_received} VND")

        # Unlock course access
        unlock_course(course_id, student_name)
        return f"Course unlocked! Check your email for login details."
    else:
        return f"Payment timed out. Please try again."

# Run the agent
asyncio.run(sell_course_to_student(
    student_name="Nguyen Van A",
    course_id="python-101",
    price=499000  # ~$20 USD
))

Line-by-line breakdown:

Integrating with Claude via MCP

If you're using Claude as your AI agent, you can expose AgentPay as an MCP tool. Create an mcp_config.json:

{
  "mcpServers": {
    "agentpay-vn": {
      "command": "agentpay-mcp",
      "env": {
        "MERCHANT_ID": "your_merchant_id",
        "BANK_CODE": "VCB",
        "ACCOUNT_NUMBER": "1234567890"
      }
    }
  }
}

Start your MCP server:

agentpay-mcp

Now Claude can call AgentPay functions directly during conversations. Example Claude conversation:

User: "I want to buy the Advanced Python course."

Claude: [calls create_payment_request tool] "Perfect! Here's your payment link: [URL]. Just scan with your banking app—should take 30 seconds."

Claude: [calls await_settlement tool] [waits for bank confirmation]

Claude: "✅ Got it! Your course access is active. I've sent login details to your email."

Real-World Walkthrough: Online Café Reservation Bot

Imagine an AI agent managing reservations and coffee sales for a café. Customer texts the agent:

Customer: "I want to book a table for 4 tomorrow at 2 PM and buy 4 cappuccinos."

Agent: "Great! That's Table 4 at 14:00 for 4 people. 4 cappuccinos = 120,000 VND. 
Let me create your payment link..."

[Agent calls create_payment_request(amount=120000, description="4 cappuccinos + table reservation")]

Agent: "Scan here to pay: [VietQR link]. Your reservation holds for 30 minutes."

[Customer scans, pays via VietQR in banking app]

[Agent's await_settlement() detects transaction]

Agent: "Confirmed! ☕ Your reservation is locked in. See you tomorrow at 2 PM!"

Comparison: AgentPay VN vs. Traditional Payment Gateways

Feature AgentPay VN Stripe / PayPal Square
Agent-native ✅ Async, non-blocking ❌ Webhook-based (complex for agents) ❌ Webhook-based
Vietnam bank direct ✅ VietQR → your account ⚠️ Requires integration layer ⚠️ Limited Vietnam support
No fund custody ✅ Your bank holds money ❌ They hold funds 2–7 days ❌ They hold funds 1–2 days
Open source ✅ MIT license ❌ Closed ❌ Closed
Setup complexity ✅ 2 lines of code ⚠️ API keys, webhooks, testing ⚠️ Similar
International support ⚠️ Vietnam-focused ✅ 200+ countries ✅ ~200 countries
Best for Vietnamese AI agents Global e-commerce Retail + online

Advanced Tips & Best Practices

1. Handle Timeouts Gracefully

Payment requests expire. Always tell users the deadline:

payment = await client.create_payment_request(
    amount=price,
    description="Course access",
    expire_in_minutes=15  # Clear deadline
)

print(f"Pay by: {payment.expires_at}")

2. Store Payment History

Link settlements to your database:

settlement = await client.await_settlement(request_id)

if settlement:
    db.save_transaction({
        "request_id": settlement.request_id,
        "transaction_id": settlement.transaction_id,
        "amount": settlement.amount_received,
        "timestamp": settlement.settled_at,
        "metadata": payment_request.metadata  # Your custom data
    })

3. Concurrent Payments

Your agent can handle multiple customers at once:

import asyncio

async def process_multiple_orders(orders):
    tasks = [
        sell_course_to_student(
            student_name=order["name"],
            course_id=order["course_id"],
            price=order["price"]
        )
        for order in orders
    ]
    results = await asyncio.gather(*tasks)
    return results

4. Leverage Metadata for Context

Store anything useful in metadata to link payments back to users:

await client.create_payment_request(
    amount=price,
    description="Service payment",
    metadata={
        "user_id": "user_12345",
        "service": "tutoring_session",
        "duration_minutes": 60,
        "tutor_id": "tutor_789"
    }
)

FAQ

Q: Does AgentPay VN hold my money?

No. The VietQR code points directly to your merchant bank account. AgentPay is purely a coordination layer—it creates requests and confirms settlements from your bank feed, but never touches funds.

Q: How do I know payment was successful?

The await_settlement() function monitors your bank account for the matching transaction. When it arrives, you get a settlement object with the transaction ID, amount, and timestamp. This is more reliable than webhooks because it's tied to your actual bank feed.

Q: Can I use AgentPay VN in production?

Yes. It's MIT-licensed open source, so you can audit the code, self-host, and run it in production immediately. Start with a test bank account to verify the flow, then switch to your real merchant account.

Q: What if the customer's payment arrives late or with a different amount?

await_settlement() includes a timeout_seconds parameter (default 600 = 10 minutes). If no matching transaction appears, it returns None. You can retry, extend the deadline, or refund the customer. For amount mismatches, the settlement.amount_received shows what actually arrived; you can flag discrepancies.

Key Takeaways

Get Started Now

You now have everything needed to let your AI agent accept VietQR payments.

Next steps:

  1. Install the SDK: pip install agentpay-vn
  2. Read the docs: https://agentpay.servicesai.vn/v1/docs
  3. Explore the repo: https://github.com/phuocdu/agentpay-vn
  4. Build something. A tutoring bot, course seller, café reservation agent, service marketplace—the pattern is the same.

Your agent is already brilliant at conversations. Now it can close the loop and get paid. Welcome to autonomous commerce.

Get started →

← All posts