Skip to main content

Quick Start

Get an AI Agent accepting QR payments in under 5 minutes. This guide walks through the complete flow — from account setup to receiving your first payment and verifying it via webhook.


Prerequisites

Before you begin, you'll need:

  1. An ItPay Platform account — Register at itpay.ai (free tier available).
  2. An API key — Generate one from the API Keys section of your dashboard. You'll receive a key like sk_live_xxxxxxxxxxxxxxxx.
  3. A supported runtime — Node.js 18+, Python 3.9+, or Go 1.21+.

That's it. No merchant account, no card processing setup, no bank verification.

info

The free tier supports up to 100 payment intents per day across all supported channels. Upgrade to a paid plan for higher limits and priority channel routing.


Step 1: Install the SDK

ItPay provides official SDKs for the three most common agent development environments.

Node.js / TypeScript

npm install @itpay/mcp

Python

pip install itpay-sdk

Go

go get github.com/itpay-ai/itpay-go

The SDKs wrap the ItPay REST API and provide typed clients for all protocol operations — ServiceManifest management, PaymentIntent creation, QR generation, and webhook verification.


Step 2: Configure Your Credentials

Set your API key and default payment channel as environment variables. These are picked up automatically by the SDK.

export ITPAY_API_KEY=sk_live_xxxxxxxxxxxxxxxx
export ITPAY_CHANNEL=alipay

Alternatively, configure them programmatically in your code:

import { ItPayClient } from '@itpay/mcp';

const client = new ItPayClient({
apiKey: 'sk_live_xxxxxxxxxxxxxxxx',
channel: 'alipay', // See the Channel Matrix for supported values
});

Supported channels: alipay, wechat, promptpay, paynow, duitnow, vietqr, gcash, usdc. See the Channel Matrix for full details on region support and settlement currencies.


Step 3: Create a ServiceManifest

A ServiceManifest is your agent's public payment declaration — it tells the world what your service does, how much it costs, and which payment channels you accept. Every paying agent needs one.

Create a manifest by posting to the ItPay API:

import { ItPayClient } from '@itpay/mcp';

const client = new ItPayClient({
apiKey: 'sk_live_xxxxxxxxxxxxxxxx',
});

const manifest = await client.manifests.create({
name: 'Smart Summary',
description: 'AI-powered document summarization — upload any PDF and get concise summaries.',
payment_methods: {
one_time: true,
},
pricing: {
one_time: [
{ amount: 99, currency: 'USD', label: 'per summary' },
],
},
accepted_channels: ['alipay', 'wechat'],
qr_mode: 'dynamic',
settlement_currency: 'USD',
endpoint: 'https://api.myservice.ai/itpay/v1',
});

console.log(`Manifest created: ${manifest.id}`);
// → Manifest created: 01J7XYKZ1A2B3C4D5E6F7G8H9I

The response includes the manifest id, which you'll use in every subsequent payment request. Store it for later use.


Step 4: Accept a Payment

This is the core flow: create a PaymentIntent, generate a QR code, and wait for the human to scan and pay.

How the payment flow works (click to expand)
  1. Your agent creates a PaymentIntent via the ItPay API.
  2. ItPay routes the intent to the chosen channel and returns a QR code URL.
  3. Your agent displays the QR code to the human user.
  4. The human scans the QR code with their wallet app (e.g., Alipay, WeChat Pay).
  5. The wallet app shows the payment amount and asks the human to confirm.
  6. After confirmation, ItPay sends a webhook to your endpoint URL.
  7. Your agent processes the webhook and delivers the service.

Here's the complete TypeScript example:

import { ItPayClient } from '@itpay/mcp';
import { randomUUID } from 'crypto';

const client = new ItPayClient({
apiKey: 'sk_live_xxxxxxxxxxxxxxxx',
channel: 'alipay',
});

async function requestPayment(): Promise<void> {
// 1. Create the PaymentIntent
const intent = await client.paymentIntents.create({
id: `pi_${randomUUID()}`, // Unique, idempotent key
service_id: '01J7XYKZ1A2B3C4D5E6F7G8H9I', // Your ServiceManifest ID
type: 'one_time',
amount: {
currency: 'CNY',
value: 699, // 6.99 CNY in minor units
},
description: 'AI document summary (42 pages)',
payer: {
agent_id: 'agent_cli_a1b2c3d4',
human_id: 'user_abc_789',
},
metadata: {
session_id: 'sess_xyz_456',
},
});

console.log(`Intent created: ${intent.id}`);
console.log(`Status: ${intent.status}`); // → "pending"

// 2. Generate the QR code
// The API returns a QRCharge with a scan URL.
const qrCharge = await client.qr.generate(intent.id);

console.log(`QR scan URL: ${qrCharge.scan_url}`);
console.log(`QR expires at: ${intent.expires_at}`);

// 3. Display the QR to the user (framework-specific)
// In a web UI: <img src={qrCharge.scan_url} alt="Pay with Alipay" />
// In a CLI: open the URL in the browser
// In a chat: send the image inline

console.log('\nWaiting for payment...');

// 4. Wait for webhook callback (see Step 5)
// The SDK provides a polling helper for development:
const result = await client.paymentIntents.waitForCompletion(intent.id, {
timeout: 300_000, // 5 minutes
pollInterval: 2_000, // poll every 2 seconds
});

if (result.status === 'succeeded') {
console.log('✓ Payment received!');
// Deliver the service...
} else {
console.log(`✗ Payment failed: ${result.status}`);
}
}

requestPayment().catch(console.error);

What happens at each step

StepComponentWhat occurs
1paymentIntents.create()ItPay validates the amount, channel, and service. Returns a pending intent.
2qr.generate()ItPay contacts the payment channel, generates a time-bound QR code, and returns the scan_url. Intent transitions to qr_generated.
3User displayThe user sees the QR code. They scan it with their wallet app.
4Wallet appThe wallet shows ¥6.99 CNY and asks for confirmation. Intent → scanningauthorized.
5WebhookItPay POSTs a signed payload to your endpoint. Your handler verifies and captures.

Step 5: Verify Payment with a Webhook Handler

When a payment completes, ItPay sends a signed webhook POST to the endpoint URL you specified in your ServiceManifest. Your handler must:

  1. Verify the HMAC signature to confirm the webhook is from ItPay (and not an attacker).
  2. Idempotency-check the event ID to prevent duplicate processing.
  3. Capture or acknowledge the payment.

Here's a complete webhook handler in Python using Flask:

import os
import hmac
import hashlib
import json

from flask import Flask, request, jsonify

app = Flask(__name__)

# Must match the webhook secret from your ItPay dashboard
WEBHOOK_SECRET = os.environ.get('ITPAY_WEBHOOK_SECRET', 'whsec_xxxxxxxxxxxxxxxx')
PROCESSED_EVENTS = set() # Use Redis or DB in production


def verify_signature(payload: bytes, signature: str, timestamp: str) -> bool:
"""Verify the HMAC-SHA256 signature on the webhook payload."""
signed_payload = f"{timestamp}.{payload.decode('utf-8')}".encode('utf-8')
expected = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
signed_payload,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)


@app.route('/itpay/v1/webhook', methods=['POST'])
def webhook():
# 1. Read headers
signature = request.headers.get('X-ItPay-Signature')
timestamp = request.headers.get('X-ItPay-Timestamp')

if not signature or not timestamp:
return jsonify({'error': 'Missing signature headers'}), 401

# 2. Verify signature
if not verify_signature(request.data, signature, timestamp):
return jsonify({'error': 'Invalid signature'}), 401

# 3. Parse event
event = request.get_json(force=True)
event_id = event['id']
event_type = event['type'] # e.g. "payment_intent.succeeded"

# 4. Idempotency check
if event_id in PROCESSED_EVENTS:
return jsonify({'status': 'already_processed'}), 200

PROCESSED_EVENTS.add(event_id)

# 5. Handle the event
if event_type == 'payment_intent.succeeded':
intent = event['data']
print(f"✓ Payment received! Intent: {intent['id']}")
print(f" Amount: {intent['amount']['value']} {intent['amount']['currency']}")
print(f" Channel: {intent['channel']}")
print(f" Metadata: {intent.get('metadata', {})}")

# TODO: Deliver the service to the user here
# - Look up session_id from intent['metadata']
# - Unlock the content or grant access
# - Update your internal database

elif event_type == 'payment_intent.failed':
intent = event['data']
print(f"✗ Payment failed: {intent['id']}{intent.get('failure_reason', 'unknown')}")

elif event_type == 'payment_intent.expired':
intent = event['data']
print(f"⏰ Payment expired: {intent['id']}")

# 6. Acknowledge receipt (200 OK)
return jsonify({'status': 'received'}), 200


if __name__ == '__main__':
app.run(port=8080)

Testing the webhook locally

# Start your webhook handler
python webhook_handler.py

# Use ngrok to expose it to the internet
ngrok http 8080
# → Forwarding https://abc123.ngrok.io → http://localhost:8080

# Update your ServiceManifest's endpoint to the ngrok URL
# https://abc123.ngrok.io/itpay/v1/webhook

Once your endpoint is live, ItPay will deliver payment events to it in real time. You can also replay missed events from the dashboard.


Next Steps

You now have an agent that can accept QR payments end-to-end. Here's where to go from here:

ResourceDescription
API ReferenceFull specification of all 9 core capabilities — broadcast, install, one-time pay, cumulative pay, subscribe, refund, void, KYC/KYB
MCP IntegrationConnect your agent using the Model Context Protocol so payment tools are auto-discovered
Architecture OverviewDeep dive into the two-layer protocol design and four-party model
Core ObjectsComplete reference for PaymentIntent, ServiceManifest, QRCharge, Subscription, and Invoice
SDK DocumentationTypeScript, Python, and Go SDK reference with full type definitions
Channel MatrixSupported channels, regions, settlement currencies, and fees
GitHubOpen-source protocol specification and reference implementations

What's next for your agent?

  • Broadcast your manifest via MCP tool discovery so any ItPay-compatible agent can find and pay your service.
  • Handle cumulative billing for usage-based pricing (e.g., per-token, per-request).
  • Offer subscriptions for recurring access with plans and quotas.
  • Integrate multiple channels so users in Thailand can pay via PromptPay, users in China via Alipay — all through the same integration.