Add VietQR Checkout to Your LLM Agent in 10 Minutes

2026-10-12 · AgentPay VN

agentpayai-agentsvietqrpythonpayments

The Problem: Your AI Agent Can Sell, But Can't Collect Money

Imagine you've built a brilliant AI agent—maybe it tutors Vietnamese students, sells digital courses, or handles café orders. It answers questions perfectly, closes deals smoothly, and users genuinely want to pay. But then what? Your agent sends them a payment link, they leave your chat, and you've lost the conversation thread. No real-time confirmation. No seamless handoff. You're back to the old world of redirects and broken flows.

That friction costs you conversions. According to recent payment data, abandonment rates spike above 20% when users must leave their application context to complete a transaction.

AgentPay VN solves this by embedding direct VietQR payment collection into your agent's conversation loop. No redirects. No money held. Just a QR code that points straight to the merchant's bank account, with instant settlement confirmation. Within 3 lines of code.


Why AgentPay VN Is Different

Before we dive into setup, let's clarify what makes AgentPay VN unique:

This is not a payment processor that takes a cut or locks you in. It's a bridge between your agent and your customer's bank.


What You'll Build in 10 Minutes

By the end of this guide, you'll have a working Python agent that:

  1. Creates a payment request when a user decides to buy
  2. Generates a checkout URL with an embedded VietQR code
  3. Waits for settlement confirmation in real time
  4. Completes the transaction without leaving the chat

We'll show you two implementations: raw SDK (for custom agents) and MCP server (for Claude and compatible platforms).


Step 1: Install AgentPay VN

Start with the Python SDK:

pip install agentpay-vn

If you're running the MCP server (for Claude):

pip install agentpay-mcp

That's it. No secret keys to paste. No OAuth flow. AgentPay VN uses your existing bank connection.


Step 2: The 3-Line Payment Flow

AgentPay VN's core is beautifully simple. Here's the canonical flow:

Creating Your First Payment Request

from agentpay_vn import PaymentClient

# Initialize the client (uses your bank config)
client = PaymentClient()

# 1. Create a payment request
payment_req = client.create_payment_request(
    amount=250000,  # 250,000 VND
    description="Advanced Vietnamese Course - 3 months access",
    order_id="course_001_user_42",  # Your internal ID
    merchant_name="AI Tutors VN"
)

# 2. Send the checkout URL to your user (via chat, SMS, etc.)
checkout_url = payment_req.checkout_url
print(f"Pay here: {checkout_url}")

# 3. Await settlement confirmation
settlement = client.await_settlement(
    payment_id=payment_req.payment_id,
    timeout_seconds=300  # 5 minutes
)

if settlement.status == "completed":
    print(f"✅ Payment confirmed! {settlement.amount} VND received.")
    # Grant course access, send invoice, etc.
else:
    print("⏱️ Payment pending or failed.")

Line-by-line explanation:

Real-World Example: A Course-Selling Bot

Let's say you're running an AI tutor that sells a 3-month Vietnamese writing course.

import asyncio
from agentpay_vn import PaymentClient

client = PaymentClient()

async def sell_course(user_id: str, course_tier: str):
    """Handle course purchase from chat."""

    prices = {
        "basic": 150000,    # 150k VND
        "premium": 350000,  # 350k VND
        "vip": 750000       # 750k VND
    }

    amount = prices.get(course_tier, 150000)

    # Step 1: Create the request
    payment = client.create_payment_request(
        amount=amount,
        description=f"Vietnamese Writing - {course_tier.title()} Tier",
        order_id=f"course_{user_id}_{course_tier}",
        merchant_name="AI Writing Tutor"
    )

    # Step 2: Tell the user
    print(f"🎓 Course access: {payment.checkout_url}")
    print(f"Amount: {amount:,} VND")
    print("Scan the QR or click the link. Settlement confirmed within 30 seconds.\n")

    # Step 3: Wait for payment
    try:
        settlement = client.await_settlement(
            payment_id=payment.payment_id,
            timeout_seconds=300
        )

        if settlement.status == "completed":
            # Grant access immediately
            grant_course_access(user_id, course_tier)
            send_invoice(user_id, amount, settlement.transaction_id)
            print(f"✅ Welcome! Your {course_tier} tier is unlocked.")
            return True
    except TimeoutError:
        print("⏰ Payment window closed. Create a new request to try again.")
        return False

def grant_course_access(user_id: str, tier: str):
    # Your logic: update DB, send link, etc.
    print(f"[DB] User {user_id} granted access: {tier}")

def send_invoice(user_id: str, amount: int, txn_id: str):
    # Your logic: email invoice
    print(f"[EMAIL] Invoice sent to user {user_id} | TXN: {txn_id}")

# Run it
asyncio.run(sell_course("user_abc_123", "premium"))

Notice how the entire transaction stays within one function. No redirect. No separate payment page. The user scans, pays, and the bot immediately confirms and unlocks the course.


Step 3: Integrate with Claude via MCP Server

If you're building an agent for Claude or another MCP-compatible platform, expose AgentPay VN as a tool:

MCP Server Configuration

Create agentpay_mcp_config.json:

{
  "name": "agentpay-vn",
  "version": "1.0.0",
  "tools": [
    {
      "name": "create_payment",
      "description": "Create a VietQR payment request. Returns checkout URL and payment ID.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "number",
            "description": "Amount in VND (e.g., 250000 for 250k)"
          },
          "description": {
            "type": "string",
            "description": "What the customer is buying"
          },
          "order_id": {
            "type": "string",
            "description": "Your internal reference ID"
          },
          "merchant_name": {
            "type": "string",
            "description": "Your business name"
          }
        },
        "required": ["amount", "description", "order_id"]
      }
    },
    {
      "name": "check_payment_status",
      "description": "Check if a payment has been settled.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "payment_id": {
            "type": "string",
            "description": "Payment ID from create_payment"
          }
        },
        "required": ["payment_id"]
      }
    }
  ]
}

Start the MCP server:

agentpay-mcp --config agentpay_mcp_config.json

Now Claude (or your AI agent) can call create_payment directly in its response:

Claude's capability:

"I've prepared a 3-month premium course for you. The cost is 350,000 VND. Let me generate a payment link..."

Claude calls: `create_payment(amount=350000, description="Premium Vietnamese Course - 3 months", order_id="user_xyz_premium", merchant_name="AI Tutors")

"Great! Scan this QR code or click here to pay. Your access will activate instantly after confirmation."

The agent never leaves the conversation. The user never leaves the app. Settlement happens in the background with bank-level confirmation.


Real-World Walkthrough: An Online Café Menu Bot

Let's say you're running a café in Hà Nội and built an AI agent to handle remote orders:

Scenario

Customer on WhatsApp:

"Hi! I want 2 cappuccinos and 1 matcha latte for delivery tomorrow at 10 AM."

Agent (powered by AgentPay VN):

  1. Confirms order: 2 cappuccinos (100k each) + 1 matcha (80k) = 280k VND
  2. Calls create_payment_request() with order details
  3. Sends checkout URL: "Pay here to confirm your 10 AM delivery: [QR + link]"
  4. Calls await_settlement() (waits max 5 minutes)
  5. On confirmation: - Marks order as paid in kitchen system - Sends: "✅ Payment confirmed! Your order is being prepared. Delivery at 10 AM to [address]. Thank you!" - SMS reminder sent to driver
  6. On failure or timeout: - "Payment not received. Your order is reserved for 10 more minutes. Resend payment link if needed."

Result: No manual intervention. No customer confusion. Orders flow directly from chat → payment → kitchen → delivery.


Do's and Don'ts

Do Don't
Create a new payment_id per customer (never reuse) Don't store bank credentials in your agent code
Use order_id to track your internal business logic Don't assume settlement is instant—use await_settlement() to wait
Set realistic timeout_seconds (300-600 for most UX flows) Don't create payments without confirming the customer's intent first
Test with the sandbox first (if available) Don't ignore settlement failures—always handle the exception
Log transaction_id for reconciliation Don't poll the API repeatedly; use webhooks or await_settlement()

Advanced Tips: Production Hardening

Idempotency: Retry Without Duplicating

If your agent crashes mid-payment, don't create a duplicate request. Use idempotency keys:

payment = client.create_payment_request(
    amount=250000,
    description="Course Access",
    order_id="course_user_42",
    idempotency_key="order_course_user_42_v1"  # Same key = same result
)

Webhook Notifications (Not Just Polling)

Instead of blocking with await_settlement(), register a webhook:

client.register_webhook(
    url="https://yourserver.com/agentpay/webhook",
    events=["settlement.completed", "settlement.failed"]
)

Your server receives a POST when payment settles. Respond with HTTP 200 to acknowledge. This scales better than polling.

Error Handling in Production

try:
    settlement = client.await_settlement(payment_id, timeout_seconds=300)
except PaymentTimeoutError:
    # Payment window closed; offer retry
    log_event(f"Payment {payment_id} timed out")
except PaymentFailedError as e:
    # Bank rejected or customer cancelled
    log_event(f"Payment failed: {e.reason}")
except Exception as e:
    # Network error, config issue, etc.
    log_event(f"Unexpected error: {e}")
    # Retry logic here

FAQ

Q: Does AgentPay VN take a fee? A: No. AgentPay VN is open-source (MIT) and free to use. It's a bridge, not a payment processor. Your bank may charge standard wire fees, but AgentPay VN doesn't.

Q: Can I use this for international customers? A: Not yet. AgentPay VN is optimized for VietQR and Vietnam's banking system. International payments require a different solution.

Q: What if a customer's payment fails? A: The agent detects the failure (settlement status ≠ "completed") and can offer to retry, refund, or suggest an alternative payment method. You have full control.

Q: How long does settlement take? A: VietQR is nearly instant at the bank level (seconds to minutes). AgentPay VN detects this via bank feed, so your agent can confirm within 30–60 seconds in most cases.


Key Takeaways


Next Steps

Ready to add payments to your agent? Here's your path forward:

  1. Install: pip install agentpay-vn
  2. Read the docs: https://agentpay.servicesai.vn/v1/docs
  3. Explore the source: https://github.com/phuocdu/agentpay-vn
  4. Build your first agent: Use the code examples above as a template.
  5. Test with a real payment: The fastest way to learn.

Whether you're selling courses, handling café orders, or running a subscription bot, AgentPay VN gets you there in 10 minutes—not 10 days. Your agent can now close the entire transaction loop without leaving the conversation.

Happy building. 🚀

Get started →

← All posts