Add VietQR Checkout to Your LLM Agent in 10 Minutes

2026-07-01 · AgentPay VN

agentpayvietqrpythonai-agentspayment-integration

Why Your AI Agent Needs Native Payment Power

Imagine you've built an AI agent that helps customers enroll in online courses. The conversation flows naturally—the bot answers questions, builds trust, and at the perfect moment, the user says: "Okay, I'm ready to buy."

Then what? Your agent can't actually accept payment. You hand off to Stripe's iframe, lose context, and watch 30% of users abandon at checkout. Or worse, you're manually processing bank transfers and chasing confirmations via Telegram.

This is where AgentPay VN changes the game. Instead of redirecting away, your agent generates a VietQR code, sends a checkout URL, and waits for the bank to confirm settlement—all without ever touching the money. The funds go straight to your merchant account.

In this tutorial, you'll add a fully functional checkout system to any LLM agent in under 10 minutes. No webhook gymnastics. No payment processing licenses. Just three Python lines and you're live.

What You'll Build: A Real Payment Flow

By the end of this guide, you'll have:

  1. An open-source Python SDK (agentpay-vn) integrated into your agent
  2. An MCP server that Claude (or any LLM) can call directly
  3. A working example: a course-enrollment bot that collects payment and confirms it

The magic: AgentPay VN uses VietQR (Vietnam's open QR standard) and bank feeds instead of APIs. Your agent creates a payment request, shares the checkout URL, and the bank settlement arrives automatically. You never hold customer funds.

Installation: 60 Seconds

Start by installing the SDK via pip:

pip install agentpay-vn

That's it. No environment variables. No secret keys. The SDK works with your bank account details (which you configure once, locally).

If you're using Claude or another agent that supports MCP (Model Context Protocol), also install the server:

pip install agentpay-mcp

Verify the installation:

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

The 3-Line Core: Payment Request → Checkout → Settlement

Here's the conceptual flow that powers everything:

from agentpay_vn import create_payment_request, await_settlement

# Step 1: Create a payment request
payment = create_payment_request(
    amount=299000,  # VND (≈ $12 USD)
    description="Python Course - Intermediate Level",
    merchant_id="YOUR_MERCHANT_ID"
)

# Step 2: Send checkout URL to user (agent returns this to the LLM)
checkout_url = payment.checkout_url
# User scans QR or clicks link, transfers via their bank app

# Step 3: Wait for settlement confirmation (bank feed)
settlement = await_settlement(payment.id, timeout=300)
if settlement.confirmed:
    print(f"Payment received: {settlement.amount} VND")
else:
    print("Payment not received within timeout")

Breaking Down create_payment_request()

This is your main entry point:

from agentpay_vn import create_payment_request, PaymentConfig

# Initialize with your merchant details (do this once, store securely)
config = PaymentConfig(
    merchant_id="1234567890",  # Your bank-linked merchant ID
    merchant_name="My Online Course",
    bank_account="1234567890123",  # Your business account
    bank_code="970010"  # Vietnam bank code (example: Vietcombank)
)

# Create a payment for a specific order
payment = create_payment_request(
    amount=500000,  # 500k VND
    description="Premium Course Bundle + Support",
    order_id="order_20250115_001",  # Your internal ref
    customer_email="student@example.com",
    config=config
)

print(payment.checkout_url)
# Output: https://agentpay.servicesai.vn/v1/checkout/pay_abc123xyz...
print(payment.qr_code)  # Raw QR code string (render as image)
print(payment.id)  # Track this for settlement

Key points: - amount is in VND (Vietnamese Dong) - order_id should be unique per transaction - The returned URL is ready to share—no additional setup - QR code data can be rendered client-side or embedded in an email

Integrating with Your LLM Agent: MCP Server Setup

If you're using Claude Desktop, VS Code, or any MCP-compatible client, AgentPay VN exposes payment functions as tools.

Step 1: Configure MCP in Claude

Edit your Claude configuration file (usually ~/.claude/config.json or settings):

{
  "mcpServers": {
    "agentpay": {
      "command": "agentpay-mcp",
      "args": [
        "--merchant-id", "1234567890",
        "--bank-account", "1234567890123",
        "--bank-code", "970010",
        "--merchant-name", "My Business"
      ]
    }
  }
}

Step 2: Test the Tool in Claude

In Claude, you can now ask:

"Create a payment request for $20 USD (approximately 500k VND) for a customer named Alice. She's buying the Python Mastery course."

Claude automatically calls the MCP tool, and returns:

{
  "checkout_url": "https://agentpay.servicesai.vn/v1/checkout/pay_xyz...",
  "amount": 500000,
  "order_id": "order_claude_1234",
  "qr_code": "00020...(raw QR string)..."
}

You can then display this to the customer or send it via email.

Real-World Example: Course Enrollment Bot

Let's build a realistic scenario: an AI agent that sells online courses via VietQR.

import asyncio
from agentpay_vn import create_payment_request, await_settlement, PaymentConfig

class CourseEnrollmentBot:
    def __init__(self, merchant_id, bank_account, bank_code):
        self.config = PaymentConfig(
            merchant_id=merchant_id,
            merchant_name="Python Academy",
            bank_account=bank_account,
            bank_code=bank_code
        )
        self.courses = {
            "python-beginner": {"price": 299000, "name": "Python Basics"},
            "python-advanced": {"price": 599000, "name": "Advanced Python"},
            "python-bundle": {"price": 899000, "name": "Complete Python Bundle"}
        }

    async def enroll_student(self, course_id: str, student_email: str):
        """
        Initiate enrollment: create payment, wait for confirmation, then grant access.
        """
        if course_id not in self.courses:
            return {"error": "Course not found"}

        course = self.courses[course_id]

        # Step 1: Create payment request
        payment = create_payment_request(
            amount=course["price"],
            description=f"Enrollment: {course['name']}",
            order_id=f"{course_id}_{student_email}_{int(asyncio.get_event_loop().time())}",
            customer_email=student_email,
            config=self.config
        )

        print(f"\n✓ Payment created: {payment.id}")
        print(f"Share this link: {payment.checkout_url}")
        print(f"Amount: {course['price']:,} VND\n")

        # Step 2: Wait for settlement (with 10-minute timeout)
        try:
            settlement = await_settlement(
                payment_id=payment.id,
                timeout=600,  # 10 minutes
                poll_interval=2  # Check every 2 seconds
            )

            if settlement.confirmed:
                print(f"✓ Payment confirmed: {settlement.amount:,} VND")
                print(f"✓ Granting access to {course['name']}...")
                # TODO: provision course access, send email with login
                return {
                    "status": "enrolled",
                    "course": course["name"],
                    "access_link": "https://academy.example.com/dashboard"
                }
            else:
                print(f"✗ Payment not received")
                return {"status": "timeout", "message": "Please try again"}

        except Exception as e:
            print(f"Error waiting for settlement: {e}")
            return {"status": "error", "message": str(e)}

# Usage
if __name__ == "__main__":
    bot = CourseEnrollmentBot(
        merchant_id="1234567890",
        bank_account="1234567890123",
        bank_code="970010"
    )

    # Async call
    result = asyncio.run(
        bot.enroll_student(
            course_id="python-advanced",
            student_email="learner@example.com"
        )
    )
    print("\nResult:", result)

What happens: 1. Student asks to enroll 2. Bot creates a payment request (VietQR checkout generated) 3. Bot shares the URL/QR with student 4. Student transfers money via their bank app 5. Bank settlement arrives automatically 6. Bot detects confirmation and provisions course access 7. Student receives welcome email with login

No manual intervention. No payment processing fees. Money goes directly to your business bank account.

Do's and Don'ts: Common Pitfalls

Do ✓ Don't ✗
Store merchant_id and bank_account securely (environment vars, vault) Hardcode credentials in public repos
Poll await_settlement() with a reasonable timeout (5–10 min) Wait indefinitely or timeout too quickly (< 30 sec)
Use unique order_id for each payment Reuse order IDs across transactions
Display the checkout URL prominently to customers Hide it or assume they'll guess the payment link
Test with small amounts first (10k VND ≈ $0.40) Deploy to production with untested flows
Listen to bank feed confirmations (settlement arrived) Assume payment is complete when QR is generated

Advanced Tips: Production Ready

1. Handle Network Timeouts Gracefully

from agentpay_vn import SettlementTimeout

try:
    settlement = await_settlement(payment.id, timeout=300)
except SettlementTimeout:
    # Log the payment for manual review, send customer a follow-up
    log_pending_payment(payment.id, customer_email)
    send_email("Your payment is being processed, we'll confirm shortly")

2. Idempotency: Handle Retries

If a network error occurs while creating a payment, the request might succeed server-side but time out client-side. Use order_id as your idempotency key:

order_id = "order_alice_python_course_20250115"
# Even if you call this twice, the second call returns the existing payment
payment = create_payment_request(
    amount=500000,
    order_id=order_id,
    description="Python Course"
)

3. Webhook Simulation for Testing

AgentPay VN doesn't require webhooks, but you can simulate bank feeds locally:

from agentpay_vn import simulate_settlement

# In your test suite
payment = create_payment_request(amount=100000, order_id="test_123")
simulate_settlement(payment.id, confirmed=True, amount=100000)

# Now await_settlement will return immediately
settlement = await_settlement(payment.id)
assert settlement.confirmed

4. Multi-Currency: Convert to VND

If your prices are in USD or another currency:

usd_price = 15.99
exchange_rate = 24500  # 1 USD = ~24,500 VND (check current rate)
vnd_amount = int(usd_price * exchange_rate)  # 391,735 VND

payment = create_payment_request(
    amount=vnd_amount,
    description=f"Item (${usd_price} USD)"
)

FAQ: Common Questions

Q: Does AgentPay VN hold my customer's money? No. The QR code points directly to your bank account. Funds arrive in your business account; AgentPay VN only verifies settlement via your bank's feed.

Q: What if a customer sends the wrong amount? The await_settlement() function checks the exact amount by default. If they send 490k instead of 500k, you can either accept a variance by setting amount_tolerance=10000 or reject and ask them to resend.

Q: Can I use AgentPay VN with Claude, OpenAI, or other LLMs? Yes. Claude via MCP (built-in). For OpenAI's API, wrap the SDK in your own tool definitions using the tools parameter. Any agent that can call Python functions can use AgentPay VN.

Q: Is there a fee? AgentPay VN is open-source (MIT license). Bank settlement fees are determined by your bank; typically 0.5–1% for business transfers in Vietnam. You get the full amount minus your bank's settlement fee—no AgentPay fee.

Key Takeaways

Get Started Now

You're ready to add checkout to your agent. Here's the next step:

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

  2. Set up your merchant config with your bank details (one-time setup).

  3. Try the example above with your LLM or Python script.

  4. Read the full docs for advanced features, webhooks, and API reference: 👉 https://agentpay.servicesai.vn/v1/docs

  5. Star the repo and contribute on GitHub: 👉 https://github.com/phuocdu/agentpay-vn

Your AI agent is now a full-fledged payment processor. In production, your first payment might arrive today. Welcome to agent-powered commerce.

Get started →

← All posts