Add VietQR Checkout to Your LLM Agent in 10 Minutes

2026-10-03 · AgentPay VN

agentpayvietqrpythonllm-agentspayments

The Problem: Your AI Agent Can't Actually Get Paid

Imagine you've built a conversational AI that helps Vietnamese customers book services, enroll in courses, or buy products. The bot engages brilliantly, answers every question, and guides users to the checkout screen—but then what? The conversation ends. The agent has no way to collect payment directly. You're stuck exporting leads or building a separate payment layer that breaks the conversational flow.

This friction costs money. Studies show that 30–40% of users abandon purchases when forced to leave their current interface. For AI-first businesses in Vietnam, this gap between agent capability and payment integration has been a real blocker.

AgentPay VN solves this by embedding a checkout tool directly into your LLM agent—no separate payment page, no redirects, no friction. In the next 10 minutes, you'll have a working payment flow.

Why AgentPay VN? The Three Core Promises

Before we code, let's clarify what makes AgentPay VN different:

1. Never Holds Your Money AgentPay VN is a thin orchestration layer. When you create a payment request, the generated VietQR code points directly at your merchant bank account. The money never touches AgentPay's systems. Your bank's payment feed confirms settlement in real time.

2. Open Source & Transparent MIT license. Full code on GitHub. No surprise fees, no vendor lock-in. You control the entire flow—run it locally, self-host the MCP server, audit every line.

3. Built for AI Agents It's not a Shopify plugin or a payment gateway API. AgentPay VN ships as a Python SDK and as an MCP (Model Context Protocol) server. Claude, local LLMs, your custom agents—they all integrate in seconds.

Installation & Setup (2 Minutes)

Step 1: Install the SDK

pip install agentpay-vn

Verify the install:

python -c "import agentpay_vn; print(agentpay_vn.__version__)"

Step 2: Get Your Merchant Info

You'll need: - Merchant ID: Your business account identifier (provided by your bank or AgentPay dashboard) - Bank Account Number: The account where payments land - Bank Code: VietQR bank code (e.g., 970436 for Techcombank, 970422 for Vietinbank)

If you don't have these yet, visit AgentPay VN Docs to register.

Step 3: Initialize Your Agent

Create a file called agent.py:

from agentpay_vn import AgentPayClient

# Initialize the client with your merchant details
client = AgentPayClient(
    merchant_id="YOUR_MERCHANT_ID",
    bank_account="123456789",
    bank_code="970436"
)

print("✓ AgentPay initialized. Ready to accept payments.")

Run it:

python agent.py

You should see the success message. You're done with setup.

The 3-Line Payment Flow

AgentPay VN distills payment collection into three steps:

Step 1: Create a Payment Request

from agentpay_vn import AgentPayClient
import time

client = AgentPayClient(
    merchant_id="YOUR_MERCHANT_ID",
    bank_account="123456789",
    bank_code="970436"
)

# Step 1: Create the payment request
payment = client.create_payment_request(
    amount=250000,  # VND
    description="Online course: Python Mastery",
    reference_id=f"course_order_{int(time.time())}",  # Unique order ID
    customer_name="Nguyễn Văn A",
    customer_phone="0912345678"
)

print(f"Payment request created: {payment.id}")
print(f"Checkout URL: {payment.checkout_url}")

What's happening: - amount: Price in VND (Vietnamese Dong). No decimals—250,000 VND for a course. - reference_id: Your internal order ID. Use this to track the payment in your database. - customer_name & customer_phone: Metadata sent with the QR. Optional but useful for reconciliation. - Return value: A Payment object with id and checkout_url.

Step 2: Send the Checkout URL to Your User

In your LLM agent conversation:

# Inside your agent's response handler
if user_confirms_purchase:
    payment = client.create_payment_request(
        amount=250000,
        description="Online course: Python Mastery",
        reference_id=f"course_order_{user_id}_{int(time.time())}",
        customer_name=user_name,
        customer_phone=user_phone
    )

    # Send the checkout URL in the agent's message
    agent_message = (
        f"Great! Your course is ready. "
        f"Scan this QR to pay 250,000 VND:\n\n"
        f"{payment.checkout_url}"
    )
    print(agent_message)

    # Store the payment ID for later confirmation
    store_payment_id(user_id, payment.id)

The checkout_url is a dynamic QR code. The user scans it with their bank app → instant bank transfer → payment confirmed.

Step 3: Wait for Settlement

# Poll for settlement (or use webhook)
import time

payment_id = "payment_abc123"
max_wait = 600  # Wait up to 10 minutes
start_time = time.time()

while time.time() - start_time < max_wait:
    status = client.await_settlement(payment_id)

    if status.is_settled:
        print(f"✓ Payment confirmed! Amount: {status.amount} VND")
        # Unlock course access, send confirmation email, etc.
        unlock_user_course(user_id)
        break

    print(f"Waiting for payment... (elapsed: {time.time() - start_time:.0f}s)")
    time.sleep(3)  # Check every 3 seconds
else:
    print("Payment timeout. User will retry.")

Key detail: await_settlement is not a blocking call. It checks the bank feed and returns the current status. In production, use webhooks (AgentPay can POST to your server when payment arrives) to avoid polling.

Real-World Example: A Course-Selling Agent

Let's build a realistic scenario: a conversational bot that sells online Python courses.

from agentpay_vn import AgentPayClient
import json
import time
from datetime import datetime

client = AgentPayClient(
    merchant_id="DEMO_MERCHANT",
    bank_account="123456789",
    bank_code="970436"
)

# Course catalog
COURSES = {
    "python101": {"name": "Python 101: Beginner", "price": 150000},
    "django": {"name": "Django Web Dev", "price": 350000},
    "fastapi": {"name": "FastAPI Advanced", "price": 450000}
}

def agent_conversation(user_id, user_name, user_phone):
    """
    Simulates an agent collecting payment.
    In reality, this would be Claude or another LLM.
    """

    print(f"Agent: Hi {user_name}! What course interests you?")
    print("Available: python101, django, fastapi")

    # User selects a course
    selected_course = "django"
    course_info = COURSES[selected_course]

    print(f"Agent: Great choice! {course_info['name']} is 10 weeks, includes projects and mentoring.")
    print(f"Price: {course_info['price']:,} VND. Ready to enroll?")

    # User confirms
    user_confirms = True

    if user_confirms:
        # Create payment
        payment = client.create_payment_request(
            amount=course_info["price"],
            description=f"Course enrollment: {course_info['name']}",
            reference_id=f"{user_id}_{selected_course}_{int(time.time())}",
            customer_name=user_name,
            customer_phone=user_phone
        )

        print(f"\nAgent: Perfect! Scan this QR to complete your payment:\n")
        print(f"{payment.checkout_url}\n")

        # Wait for payment (simplified)
        print("Waiting for bank confirmation...")
        start = time.time()

        while time.time() - start < 60:  # Wait 1 minute max
            status = client.await_settlement(payment.id)

            if status.is_settled:
                print(f"\n✓ Payment received! {status.amount:,} VND confirmed.")
                print(f"Agent: Enrollment complete! Welcome to {course_info['name']}.")
                print(f"Check your email for login credentials and course materials.")

                # Log the transaction
                log_transaction(user_id, selected_course, status.amount, datetime.now())
                return True

            time.sleep(2)

        print("Payment timeout. Please try again.")
        return False

def log_transaction(user_id, course_id, amount, timestamp):
    """Record the transaction in your database."""
    record = {
        "user_id": user_id,
        "course_id": course_id,
        "amount_vnd": amount,
        "timestamp": timestamp.isoformat()
    }
    print(f"Logged: {json.dumps(record)}")

# Run the agent
agent_conversation(
    user_id="user_123",
    user_name="Trần Thị B",
    user_phone="0987654321"
)

Output:

Agent: Hi Trần Thị B! What course interests you?
Available: python101, django, fastapi
Agent: Great choice! Django Web Dev is 10 weeks, includes projects and mentoring.
Price: 350,000 VND. Ready to enroll?

Agent: Perfect! Scan this QR to complete your payment:

https://agentpay.servicesai.vn/checkout/pay_xyz789...

Waiting for bank confirmation...
✓ Payment received! 350,000 VND confirmed.
Agent: Enrollment complete! Welcome to Django Web Dev.
Check your email for login credentials and course materials.
Logged: {"user_id": "user_123", "course_id": "django", "amount_vnd": 350000, "timestamp": "2024-12-20T14:30:15.123456"}

Connecting to Claude with MCP

If you're using Claude or another LLM via the Model Context Protocol, no need to build custom agent code. AgentPay ships an MCP server.

Install the MCP Server

pip install agentpay-mcp

Configure Claude

Add to your Claude client config (e.g., ~/.claude/config.json or environment):

{
  "mcp_servers": [
    {
      "name": "agentpay",
      "command": "agentpay-mcp",
      "env": {
        "AGENTPAY_MERCHANT_ID": "YOUR_MERCHANT_ID",
        "AGENTPAY_BANK_ACCOUNT": "123456789",
        "AGENTPAY_BANK_CODE": "970436"
      }
    }
  ]
}

Restart Claude. Now Claude has access to: - agentpay.create_payment_request(amount, description, reference_id, customer_name, customer_phone) - agentpay.await_settlement(payment_id) - agentpay.get_payment_status(payment_id)

Ask Claude: "Help me sell a course for 500,000 VND and collect payment." Claude will orchestrate the entire flow without you writing additional code.

Best Practices: Do's and Don'ts

✓ Do ✗ Don't
Store reference_id in your database before showing the QR Reuse the same reference_id for multiple payments
Use webhooks in production (avoid polling) Poll more than every 2 seconds; you'll hit rate limits
Set a reasonable timeout (5–10 min) for user payment Wait indefinitely; expire abandoned payments after 15 min
Include customer metadata (name, phone) for audits Leave customer fields empty; you'll lose reconciliation data
Test with your actual merchant account first Go live without testing settlement flow end-to-end
Handle both settled and failed payments gracefully Assume all payments succeed; always check is_settled

FAQ

Q: Does AgentPay VN hold my money? No. The VietQR code points directly to your merchant bank account. Your bank receives and confirms the transfer. AgentPay only orchestrates; it never touches the funds.

Q: Can I use this with Gemini, GPT-4, or local LLMs? Yes. Via MCP, any LLM that supports the Model Context Protocol can call AgentPay. You can also call the Python SDK directly from any agent framework (Langchain, AutoGen, etc.).

Q: How do I know when payment arrives? Two options: 1. Polling (quick setup): Call await_settlement(payment_id) every few seconds. 2. Webhooks (production): AgentPay POSTs to your endpoint when bank confirms payment. See docs for webhook setup.

Q: What if a user scans the QR but doesn't have enough balance? Their bank app will reject the transaction. await_settlement will return is_settled=False. Your agent can prompt them to retry or choose a lower-priced option.

Q: Can I accept international payments (not VND)? Currently, AgentPay VN is optimized for VietQR (Vietnamese domestic transfers). International support is on the roadmap.

Key Takeaways

Get Started Now

You've got everything you need to add payments to your agent in the next 10 minutes.

Next steps:

  1. Install: pip install agentpay-vn
  2. Explore examples: Visit the GitHub repo for more sample agents and configurations.
  3. Read the full docs: AgentPay VN Docs cover webhooks, error handling, multi-currency flows, and testing.
  4. Join the community: Share your agent builds on GitHub Discussions. Report issues. Contribute.

Your conversational commerce engine is ready. Build something amazing.

Get started →

← All posts