AI Agent VietQR Payments in Python: Step-by-Step Guide

2026-08-05 · AgentPay VN

pythonvietqrai-agentspayment-apimcp-server

The Problem: Your AI Agent Needs to Get Paid

You've built a smart chatbot that sells online courses. It answers questions, builds trust, and users are ready to buy—but then they hit a wall. Your AI agent has no way to collect payment. You could bolt on Stripe or PayPal, but those charge 2-3% + fixed fees, add foreign exchange friction, and lock your Vietnamese customers into USD workflows. Even worse, you'd need to hold user funds temporarily, creating compliance headaches.

For Vietnamese merchants and global businesses serving Vietnam, there's a better way: VietQR—a bank-agnostic QR code standard that routes payments directly to your bank account in seconds. And now, your AI agent can handle the entire flow natively.

Enter AgentPay VN: an MIT-licensed Python SDK that lets any AI agent create VietQR payment requests, send checkout URLs, and confirm settlement—all without touching money. In this tutorial, you'll learn exactly how to make your Python agent a payment-collecting machine.

What Is AgentPay VN and Why Use It?

AgentPay VN is a lightweight open-source SDK + MCP server purpose-built for integrating VietQR payments into AI workflows. Here's what makes it different:

Why this matters: Your AI agent can now say, "Great! Here's your payment link," collect the money, and fulfill the order—all in one conversation. No manual reconciliation. No payment gateway fees eating your margins. No currency conversion losses.

Getting Started: Installation and Basic Setup

Step 1: Install the SDK

Open your terminal and install AgentPay VN via pip:

pip install agentpay-vn

That's it. No environment variables, no complex initialization—yet.

Step 2: Understand the 3-Line Payment Flow

Before you write code, understand the mental model:

  1. create_payment_request – Generate a payment request with an amount, description, and merchant details.
  2. send checkout_url – Deliver that request as a clickable VietQR URL to your user.
  3. await_settlement – Listen for bank confirmation that the payment landed.

That's the entire cycle. Your agent asks for money, sends a link, waits for confirmation. Done.

Building Your First Payment-Enabled Agent

Real-World Example: A Vietnamese Language Course Bot

Imagine you're selling a 5-week Vietnamese language course for ₫500,000 (about $20 USD). A customer finishes the preview lesson and is ready to enroll. Here's how your agent handles it:

from agentpay_vn import PaymentClient, PaymentRequest
import asyncio

# Initialize the client with your merchant info
# In production, load these from environment variables
client = PaymentClient(
    merchant_id="YOUR_MERCHANT_ID",           # Your unique ID
    merchant_name="Vietnamese Learning Co",   # Display name
    bank_account="1234567890",               # Your bank account
    bank_code="970432"                       # VietComBank (VCCB)
)

# Step 1: Create a payment request
payment_req = PaymentRequest(
    amount=500000,                            # ₫500,000
    description="5-week Vietnamese A1 course",
    reference_id="course_001_user_jane",    # Track this order
    callback_url="https://yourdomain.com/webhook"  # Optional: get notified
)

# Step 2: Generate the VietQR checkout URL
checkout_url = client.create_payment_request(payment_req)
print(f"Send this to the customer: {checkout_url}")
# Output: https://vietqr.io/checkout?token=abc123xyz...

# Step 3: Wait for settlement confirmation
async def wait_for_payment(request_id: str, timeout_seconds: 300):
    settlement = await client.await_settlement(
        request_id=request_id,
        timeout=timeout_seconds
    )
    if settlement.confirmed:
        print(f"✓ Payment confirmed! {settlement.amount} VND from {settlement.payer_name}")
        # Trigger course enrollment
        enroll_user_in_course("jane", "course_001")
        return True
    else:
        print(f"✗ Payment expired or cancelled")
        return False

# Run the async settlement check
result = asyncio.run(wait_for_payment("course_001_user_jane", timeout_seconds=600))

Line-by-line breakdown:

Error Handling and Edge Cases

In production, things go wrong. Here's a robust version:

from agentpay_vn import PaymentClient, PaymentRequest, SettlementError

async def safe_payment_flow(user_id: str, course_id: str, amount: int):
    client = PaymentClient(
        merchant_id="YOUR_MERCHANT_ID",
        merchant_name="Vietnamese Learning Co",
        bank_account="1234567890",
        bank_code="970432"
    )

    try:
        # Create request
        req = PaymentRequest(
            amount=amount,
            description=f"Enrollment: {course_id}",
            reference_id=f"{user_id}_{course_id}_{int(time.time())}"
        )
        url = client.create_payment_request(req)

        # Wait for settlement (5-minute default timeout)
        settlement = await client.await_settlement(
            request_id=req.reference_id,
            timeout=300
        )

        if settlement.confirmed:
            return {"status": "success", "amount": settlement.amount}
        else:
            return {"status": "expired", "message": "User didn't pay in time"}

    except SettlementError as e:
        # Network issue, bank unreachable, etc.
        return {"status": "error", "message": str(e)}
    except ValueError as e:
        # Invalid merchant config or request
        return {"status": "invalid", "message": str(e)}

This wraps the payment flow in try-except blocks. If the bank feed is temporarily down, you'll catch it and retry.

Integrating with AI Agent Frameworks (MCP Server)

If you're using Claude or another agent that supports MCP (Model Context Protocol), AgentPay VN provides a drop-in MCP server. This lets your agent call payment functions just like any other tool.

Step 1: Start the MCP Server

agentpay-mcp --merchant-id YOUR_ID --bank-account 1234567890 --bank-code 970432

The server starts on stdio by default (compatible with Claude Desktop).

Step 2: Configure Claude to Use It

Edit your Claude Desktop config file:

macOS/Linux: ~/.config/Claude/claude_desktop_config.json Windows: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "agentpay-vn": {
      "command": "agentpay-mcp",
      "args": [
        "--merchant-id", "YOUR_MERCHANT_ID",
        "--bank-account", "1234567890",
        "--bank-code", "970432",
        "--callback-url", "https://yourdomain.com/webhook"
      ],
      "env": {
        "LOG_LEVEL": "info"
      }
    }
  }
}

Restart Claude. It will now have three new tools: - create_payment_request(amount, description, reference_id) - get_payment_status(reference_id) - await_settlement(reference_id, timeout_seconds)

Now your agent can natively handle payments in conversation:

User: "I want to buy the advanced course." Agent: "Great! That's ₫750,000. Let me create a payment request for you." [Agent calls create_payment_request tool] Agent: "Here's your payment link: [QR code URL]. Scan it with any banking app. I'll confirm once the payment lands." [Agent calls await_settlement tool] Agent: "✓ Payment received! I'm adding you to the course now. You'll get an email with your login in 2 minutes."

Do's and Don'ts: Best Practices

✅ Do ❌ Don't
Use unique reference_id for each order (include user ID + timestamp) Reuse the same reference_id for multiple payments
Store the checkout URL in your database before sending it Assume the URL is permanent; generate fresh ones per request
Set timeout to 5-10 minutes for user-initiated payments Use a 60+ minute timeout (users expect instant feedback)
Log settlement confirmations for reconciliation Trust in-memory state; always persist to a database
Handle SettlementError exceptions explicitly Let errors crash your agent silently
Load merchant ID and bank account from env vars in production Hardcode credentials in source code
Implement idempotency: check if order already exists before creating a new request Create duplicate payment requests on network retry

Advanced: Webhook Notifications

Instead of polling with await_settlement, you can register a webhook to get instant notifications:

from agentpay_vn import PaymentRequest

payment_req = PaymentRequest(
    amount=500000,
    description="Course enrollment",
    reference_id="user_123_course_a",
    callback_url="https://yourdomain.com/agentpay/webhook"  # Your endpoint
)

url = client.create_payment_request(payment_req)

When the payment settles, AgentPay VN will POST a signed JSON payload to your webhook:

{
  "event": "settlement_confirmed",
  "reference_id": "user_123_course_a",
  "amount": 500000,
  "payer_bank": "vietcombank",
  "payer_name": "Jane Tran",
  "timestamp": "2025-01-15T10:32:00Z",
  "signature": "hmac_sha256_signature"
}

Verify the signature using your merchant secret (provided on setup) and process the order. This is faster and more reliable than polling for high-volume scenarios.

Walkthrough: Building a Café Ordering Bot

Let's imagine a Vietnamese coffee café in HCMC that uses an AI agent to handle online orders:

  1. Customer starts chat: "I'd like 2 iced coffees and a pastry."
  2. Agent confirms order: "That's 2 x Cà Phê Đá (35K) + 1 x Croissant (45K) = 115,000 VND. Ready to pay?"
  3. Agent creates payment request for ₫115,000 with reference_id="order_cafe_2025_0115_001".
  4. Agent sends QR code: "Scan this with your banking app to pay."
  5. Customer scans and pays via their bank app (VietComBank, Techcombank, etc.). The money goes directly to the café's account.
  6. Bank confirms settlement in 15-30 seconds. AgentPay VN receives the confirmation.
  7. Agent confirms: "✓ Payment received! Your order will be ready in 10 minutes. Pickup at counter A."
  8. Agent logs the order to the café's kitchen system and sends an SMS.

No payment processor. No fees. No fraud risk. Money lands straight in the café's account.

FAQ

Q: Does AgentPay VN hold my money?

A: Absolutely not. AgentPay VN never touches user funds. The VietQR code points directly to your bank account. AgentPay VN only coordinates the request and confirms settlement. Your bank holds the money for 0-2 business days (standard settlement), not AgentPay VN.

Q: What if a payment fails or times out?

A: If the customer doesn't pay within the timeout (default 5 minutes), await_settlement returns confirmed=False. You can then offer to regenerate a new payment link or suggest alternative payment methods. No money is charged.

Q: Which banks does AgentPay VN support?

A: It works with any Vietnamese bank that supports VietQR (the standard QR code format). That includes Vietcombank, Techcombank, ACB, Agribank, VP Bank, and 40+ others. Use the bank code (e.g., 970432 for Vietcombank) when initializing the client.

Q: Can I use AgentPay VN for international agents (like GPT-4)?

A: Yes! The Python SDK works anywhere. The MCP server works with any agent that supports MCP (Claude, upcoming integrations). If you're building a custom agent, just call the SDK—no framework required.

Key Takeaways

Get Started Now

Your AI agent can accept VietQR payments today. Here's how:

  1. Install the SDK: bash pip install agentpay-vn

  2. Grab your merchant ID from your bank or sign up at https://agentpay.servicesai.vn/v1/docs.

  3. Follow the examples above in your agent code or MCP config.

  4. Read the full docs at https://agentpay.servicesai.vn/v1/docs for bank codes, webhook signatures, and more.

  5. Contribute or report issues on GitHub: https://github.com/phuocdu/agentpay-vn.

Your AI agent is now a payment-collecting machine. Go build something incredible.

Get started →

← All posts