Sell Digital Products from AI Chatbot Without Holding Funds

2026-08-09 · AgentPay VN

ai-paymentsvietqrpython-sdkdigital-productsmcp-server

The Problem: Why Most AI Commerce Startups Hit a Compliance Wall

Imagine you've built a brilliant AI chatbot that sells online courses, design templates, or software licenses. Your bot engages customers perfectly, the conversion rate is solid—but then you hit the regulatory brick wall.

You're being asked to hold customer funds, get a payment institution license, maintain segregated accounts, and comply with financial regulations that were written before AI agents existed. Suddenly, your indie project or startup needs lawyers, compliance officers, and a mountain of paperwork just to process payments.

Worse: you're holding money that isn't yours, creating liability and trust issues with both customers and regulators.

There's a better way. What if your AI agent could collect payments without ever touching the money?

Why Direct Bank Settlement Changes the Game

AgentPay VN solves this by doing something elegant: the payment flow points directly at your merchant bank account via VietQR codes. No intermediary holdings. No escrow accounts. No special licenses.

Here's the architecture:

  1. Your AI agent calls create_payment_request() when a customer wants to buy
  2. A VietQR QR code is generated pointing to your bank account
  3. Customer scans and pays using their banking app
  4. Bank feed confirms the settlement
  5. Agent delivers the product (instantly or with webhook verification)

The entire transaction flow—from sale initiation to delivery—happens with zero fund custody. Your agent is an orchestrator, not a money handler.

Getting Started: Installation and Setup

Step 1: Install the SDK

pip install agentpay-vn

The package includes the core Python SDK plus CLI utilities. For AI agent integration, you'll also want the MCP server:

pip install agentpay-mcp

Step 2: Configure Your Merchant Details

Create a simple config file or environment variables with your merchant information:

# config.py
import os
from agentpay_vn import MerchantConfig

merchant = MerchantConfig(
    merchant_id="YOUR_MERCHANT_ID",
    merchant_name="Your Business Name",
    bank_account="YOUR_VIETQR_ENABLED_ACCOUNT",
    bank_code="BIDV",  # or ACB, Vietcombank, etc.
)

Your bank account must support VietQR (most Vietnamese banks do as of 2024). Check with your bank if unsure.

Step 3: Set Up MCP Server for Claude Integration

If you're building an agent that runs on Claude or similar LLM platforms, configure the MCP server:

{
  "mcpServers": {
    "agentpay": {
      "command": "python",
      "args": ["-m", "agentpay_mcp"],
      "env": {
        "MERCHANT_ID": "YOUR_MERCHANT_ID",
        "MERCHANT_NAME": "Your Business",
        "BANK_ACCOUNT": "YOUR_ACCOUNT_NUMBER",
        "BANK_CODE": "BIDV"
      }
    }
  }
}

This exposes AgentPay functions as tools your AI agent can call directly.

The Core Workflow: 3-Line Payment Flow

At its heart, AgentPay VN is built on three core operations:

Create Payment Request

from agentpay_vn import PaymentClient, PaymentRequest

# Initialize client
client = PaymentClient(merchant_id="YOUR_ID", bank_account="123456789")

# Create a payment request for a digital product
request = PaymentRequest(
    request_id="course_001_user_42",  # Unique identifier
    amount_vnd=299000,                  # Price in Vietnamese Dong
    description="Python Mastery Online Course",
    customer_phone="0987654321",       # Optional but useful
    metadata={                          # Custom data for your bot
        "product_type": "course",
        "course_id": "python-101",
        "user_id": "user_42",
        "delivery_method": "email"
    }
)

# Generate VietQR QR code
qr_response = client.create_payment_request(request)
print(f"QR Code URL: {qr_response.qr_url}")
print(f"Checkout URL: {qr_response.checkout_url}")

What happens here: - request_id must be unique per transaction; use UUIDs or timestamp combos - amount_vnd is the total; no decimal places (VND is whole numbers) - metadata stores context your agent needs later (product ID, user ID, etc.) - The returned qr_url can be displayed in your chatbot interface

Send Checkout URL to Customer

Your AI agent displays the QR or sends the checkout URL:

# In your chatbot logic
def sell_product(user_id, product_id, price_vnd):
    request = PaymentRequest(
        request_id=f"{product_id}_{user_id}_{int(time.time())}",
        amount_vnd=price_vnd,
        description=f"Purchase: {product_id}",
        metadata={"user_id": user_id, "product_id": product_id}
    )

    response = client.create_payment_request(request)

    message = (
        f"Great! Here's your checkout link:\n"
        f"{response.checkout_url}\n\n"
        f"Or scan this QR code in your banking app.\n"
        f"Once paid, you'll get instant access!"
    )
    return message, response

Await Settlement and Deliver Product

import time
from agentpay_vn import SettlementChecker

# Poll for settlement confirmation
checker = SettlementChecker(client)

def deliver_on_payment(request_id, user_id, product_id, timeout_seconds=300):
    """
    Wait for payment, then deliver product.
    """
    start_time = time.time()

    while time.time() - start_time < timeout_seconds:
        settlement = checker.await_settlement(
            request_id=request_id,
            poll_interval=3  # Check every 3 seconds
        )

        if settlement.status == "CONFIRMED":
            print(f"✓ Payment confirmed! Transaction: {settlement.transaction_id}")
            print(f"  Amount: {settlement.amount_vnd} VND")
            print(f"  Bank reference: {settlement.bank_ref}")

            # Deliver the product
            deliver_course(user_id, product_id)
            send_email(user_id, generate_download_link(product_id))

            return {"status": "delivered", "transaction": settlement.transaction_id}

        time.sleep(3)

    raise TimeoutError(f"Payment not received within {timeout_seconds}s")

Key points: - await_settlement() polls the bank feed; confirmations typically arrive within 10-30 seconds - The metadata you stored earlier is included in the settlement object - Once confirmed, your agent can immediately deliver the digital product - Use transaction_id for your records and customer receipts

Real-World Example: AI Course Selling Bot

Let's walk through a complete scenario: an AI chatbot that sells a Python course.

Setup: - Course price: 299,000 VND - Merchant: "AI Academy" - Delivery: Instant email with access link

User interaction:

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

Bot: "Excellent choice! The Python Mastery course is 299,000 VND. 
      Would you like to proceed?"

User: "Yes, please."

Bot: [Calls create_payment_request]
     "Great! Here's your checkout link: [URL]

      Or scan this QR code in your banking app. Payment takes about 
      10-30 seconds to confirm. You'll get instant access once paid!"

User: [Opens banking app, scans QR, transfers 299,000 VND]

Bot: [Polls await_settlement every 3 seconds]
     [After 15 seconds, settlement confirmed]

     "Perfect! Payment received! 🎉

      Here's your access link: [download_link]
      Login credentials sent to your email.

      Enjoy the course! Email us if you have questions."

Backend code:

from datetime import datetime
import uuid

class CourseBot:
    def __init__(self, client):
        self.client = client
        self.checker = SettlementChecker(client)

    async def handle_purchase_request(self, user_id, course_id):
        # Look up course price
        courses = {
            "python-101": {"name": "Python Mastery", "price": 299000},
            "web-dev": {"name": "Web Dev Bootcamp", "price": 599000},
        }

        course = courses.get(course_id)
        if not course:
            return {"error": "Course not found"}

        # Create payment request
        request = PaymentRequest(
            request_id=f"{course_id}_{user_id}_{uuid.uuid4().hex[:8]}",
            amount_vnd=course["price"],
            description=f"Course: {course['name']}",
            metadata={
                "user_id": user_id,
                "course_id": course_id,
                "timestamp": datetime.now().isoformat()
            }
        )

        qr_response = self.client.create_payment_request(request)

        return {
            "checkout_url": qr_response.checkout_url,
            "qr_url": qr_response.qr_url,
            "request_id": request.request_id,
            "amount": course["price"]
        }

    async def await_and_deliver(self, request_id, user_id, course_id):
        settlement = self.checker.await_settlement(
            request_id=request_id,
            poll_interval=3
        )

        if settlement.status == "CONFIRMED":
            # Generate access link
            access_link = self.generate_course_link(user_id, course_id)

            # Send email
            self.send_confirmation_email(
                user_id,
                course_id,
                access_link,
                settlement.amount_vnd
            )

            return {
                "status": "delivered",
                "access_link": access_link,
                "transaction_id": settlement.transaction_id
            }

Best Practices: Do's and Don'ts

✅ Do ❌ Don't
Use unique request_id per transaction (UUID or timestamp-based) Reuse request IDs; this breaks settlement matching
Store metadata with user/product context for delivery logic Rely solely on request_id; metadata is essential
Set polling intervals to 3-5 seconds for fast delivery UX Poll every second (wastes bandwidth) or every 60s (slow UX)
Log transaction_id and bank_ref for audit trails Ignore bank references; you need these for disputes
Use timeout logic (300-600 seconds) to prevent infinite waits Wait indefinitely without a timeout
Test with small amounts first (10,000-50,000 VND) Go live with untested flows
Handle network errors gracefully (retry with backoff) Assume perfect connectivity

Advanced Tips for Production

1. Idempotency and Retries

Network hiccups happen. Implement idempotent delivery:

def deliver_product_idempotent(transaction_id, user_id, product_id):
    # Check if already delivered
    if is_delivery_record_exists(transaction_id):
        return get_existing_delivery(transaction_id)

    # Deliver and record
    result = deliver_course(user_id, product_id)
    record_delivery(transaction_id, user_id, product_id, result)
    return result

2. Webhook Notifications (Future Enhancement)

Polling works, but for high-volume stores, consider webhook callbacks once AgentPay VN adds them:

# Pseudocode for future webhook support
request = PaymentRequest(
    request_id="...",
    amount_vnd=299000,
    description="Course",
    webhook_url="https://yourbot.com/agentpay/settlement"
)

3. Logging and Analytics

Track payment flows for insights:

import logging

logger = logging.getLogger("agentpay_sales")

logger.info(
    f"Payment created: request_id={request.request_id}, "
    f"user={metadata['user_id']}, amount={request.amount_vnd}"
)
logger.info(f"Settlement confirmed: txn_id={settlement.transaction_id}")

4. Multi-Currency (Future)

Currently, AgentPay VN works in VND only. If you serve international customers, implement a conversion layer:

USD_TO_VND = 24500  # Approximate

def price_in_vnd(usd_amount):
    return int(usd_amount * USD_TO_VND)

FAQ

Q: Does AgentPay VN hold my customer's money? A: No. The VietQR code points directly to your merchant bank account. Settlement goes straight to your bank account within minutes. AgentPay VN is a payment orchestration layer only.

Q: Do I need a special license to use this? A: Not for basic payment orchestration. You're not a payment institution—you're simply directing customers to pay your merchant account. However, always check local regulations or consult a lawyer if required.

Q: What if a customer disputes a payment? A: Bank reference (bank_ref) and transaction ID are logged. You can provide these to your bank or customer for dispute resolution. AgentPay VN logs all details for audit trails.

Q: Can I use this for subscription or recurring payments? A: Currently, AgentPay VN handles one-off payments. For subscriptions, create a new payment request each billing cycle and track it separately in your bot logic.

Q: How long does settlement confirmation take? A: Typically 10-30 seconds. Some banks are faster. The await_settlement() function polls until confirmed; set a timeout appropriate for your UX (300-600 seconds is reasonable).

Key Takeaways

Next Steps

Ready to build?

  1. Install AgentPay VN: pip install agentpay-vn
  2. Read the full docs: https://agentpay.servicesai.vn/v1/docs
  3. Explore the GitHub repo: https://github.com/phuocdu/agentpay-vn
  4. Start with a test flow: Use small amounts (10k-50k VND) to verify your setup
  5. Deploy your AI agent: Sell digital products with confidence

Your AI chatbot is about to become a sales engine—without the compliance headaches. Let's build.

Get started →

← All posts