Observed since 20 Oct, 22:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
agentpay-vn
VietQR payment infrastructure for AI agents — AgentPay VN MCP server & Python SDK
VietQR payment infrastructure for AI agents — collect money inside any conversation.
AgentPay VN lets AI agents (Claude, GPT, custom bots) generate payment QR codes, send them to users, and automatically confirm when the money arrives — all without ever holding or touching funds. Money flows directly from the payer's bank account into the merchant's account; AgentPay only reads the bank transaction feed to confirm settlement.
Status: Early access / self-hosted — running on the same swarm as Sổ Nợ AI.
AI Agent AgentPay API Bank feed (SePay)
| | |
|-- create_payment_request ->| |
|<- { qr_image_url, id } ----| |
| | |
|-- send QR to user -------->| |
| | user scans & pays |
| |<-- webhook (bank txn) ----|
| |-- match AP* pay_code |
| |-- status → settled |
|<-- await_settlement done --| |
| | |
|-- deliver order / unlock ->| |
POST /v1/payment-requests → gets a VietQR image URL and a checkout page.await_settlement() (or the MCP tool) to poll until status = settled.AgentPay never holds money. The QR points directly at the merchant's bank account number. The platform only monitors the bank transaction feed to detect matching transfers.
pip install agentpay-vn
A sandbox key is self-serve and instant:
curl -X POST https://agentpay.servicesai.vn/v1/sandbox/register \
-H "Content-Type: application/json" -d '{"shop_name": "My Bot"}'
# -> { "api_key": "ap_test_...", "expires_at": "..." }
export AGENTPAY_API_KEY=ap_test_xxx
From Python: register_sandbox(). From an agent: just call the register_sandbox
MCP tool — it issues the key and applies it to the session.
Sandbox keys last 7 days, move no real money, and renew by calling the same endpoint
with the same email. For real payments you need an ap_live_* key, which requires a
registered merchant with a Vietnamese bank account — sign up at
agentpay.servicesai.vn.
from agentpay.client import AsyncAgentPayClient, await_settlement
import asyncio
async def main():
async with AsyncAgentPayClient("ap_test_xxx") as client:
pr = await client.create_payment_request(amount=50_000, description="Order #1")
print(pr["checkout_url"]) # send this link to your user
result = await await_settlement(client, pr["id"], timeout=120)
assert result["status"] == "settled"
asyncio.run(main())
See examples/quickstart.py for the full runnable version.
AgentPay ships an MCP server so any MCP-compatible AI agent can call it as a tool — no extra code needed.
Add to claude_desktop_config.json (or use examples/claude_desktop_config.json):
{
"mcpServers": {
"agentpay": {
"command": "python",
"args": ["-m", "agentpay.mcp_server"],
"env": {
"AGENTPAY_API_KEY": "ap_test_xxx",
"AGENTPAY_BASE_URL": "https://agentpay.servicesai.vn/v1"
}
}
}
}
Or use the installed console script:
{
"mcpServers": {
"agentpay": {
"command": "agentpay-mcp",
"env": { "AGENTPAY_API_KEY": "ap_live_xxx" }
}
}
}
| Tool | Description |
|---|---|
register_sandbox | Self-issue a free ap_test_* key — call this first when no key is set |
create_payment_request | Generate a VietQR code for a given amount |
check_payment | Get current status of a payment request |
await_settlement | Poll until payment arrives or timeout (max 600 s) |
list_recent_payments | List last N settled transactions |
The MCP server gives an agent the tools. The bundled skill gives it the judgement:
when to charge, how to format a VND amount, and the rule that nothing ships before
status = settled. See skills/agentpay-vn/SKILL.md.
This repository is also a Claude Code plugin marketplace, so the skill and the MCP server install together in one step:
claude plugin marketplace add phuocdu/agentpay-vn
claude plugin install agentpay-vn@agentpay-vn
Claude Code prompts for your API key (stored in the OS credential store, not in
settings.json). Leave it blank to start in sandbox — the agent will call
register_sandbox on its first charge.
For other agents, copy skills/agentpay-vn/ into wherever that agent reads skills from,
and add the MCP server as shown above.
from agentpay.client import AgentPayClient
with AgentPayClient("ap_live_xxx") as client:
# Create
pr = client.create_payment_request(
amount=150_000,
description="Consulting session 30 min",
ttl_minutes=30,
idempotency_key="session-abc-123",
)
# Poll manually
import time
for _ in range(60):
pr = client.get_payment_request(pr["id"])
if pr["status"] != "pending":
break
time.sleep(5)
# Reconcile
txns = client.list_transactions(limit=10)
from agentpay.client import AsyncAgentPayClient, await_settlement
async with AsyncAgentPayClient("ap_live_xxx") as client:
pr = await client.create_payment_request(amount=75_000, description="eBook download")
result = await await_settlement(client, pr["id"], timeout=300)
if result["status"] == "settled":
send_download_link(result["metadata"].get("email"))
import hashlib, hmac
def verify_webhook(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header)
Register a webhook endpoint:
ep = client.register_webhook(
url="https://your-server.com/webhooks/agentpay",
events=["payment.settled", "payment.expired"],
)
print(ep["secret"]) # store this — shown only once
agentpay-openapi.yamlhttps://agentpay.servicesai.vn/v1Authorization: Bearer ap_live_xxx (or ap_test_xxx for sandbox)| Method | Path | Description |
|---|---|---|
POST | /v1/payment-requests | Create payment request |
GET | /v1/payment-requests/{id} | Get status |
POST | /v1/payment-requests/{id}/cancel | Cancel pending request |
GET | /v1/transactions | List settled transactions |
POST | /v1/webhook-endpoints | Register webhook URL |
POST | /v1/sandbox/simulate-settlement | Simulate payment (sandbox only) |
GET | /pay/{pay_code} | Public checkout page (HTML, mobile-friendly) |
AgentPay runs as part of the Sổ Nợ AI FastAPI backend.
agentpay.servicesai.vn vhost| Variable | Default | Description |
|---|---|---|
AGENTPAY_BASE_URL | https://agentpay.servicesai.vn | Public base URL for checkout links |
MONGO_URI | mongodb://localhost:27017 | Inherited from Sono |
BILLING_WEBHOOK_TOKEN | — | SePay webhook token (inherited) |
curl -X POST https://sono.servicesai.vn/api/admin/agentpay/keys \
-H "Authorization: Bearer <admin-jwt>" \
-H "Content-Type: application/json" \
-d '{"org_id": "<shop-user-id>", "name": "My bot", "livemode": true}'
The response includes the full key — store it immediately; it is shown only once.
| Tier | Settled payments/month | Requests/minute |
|---|---|---|
| Free | 50 | 120 |
No money held — QR codes point directly at the merchant's bank account. AgentPay only reads the transaction feed; it never touches the money.
Idempotency — pass an Idempotency-Key header on POST /payment-requests to safely retry without creating duplicates (24-hour deduplication window).
HMAC webhook verification — every outbound webhook is signed with HMAC-SHA256(whsec_..., raw_body) in the AgentPay-Signature header. Always verify before processing.
Sandbox — use ap_test_* keys and POST /v1/sandbox/simulate-settlement to develop and test without real transactions.
Minimal trust surface — the MCP server is a thin REST client with no local secrets beyond the API key. Compromising an agent key only exposes one tenant's payment-request creation ability.
MIT © 2026 ServicesAI — see LICENSE.
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
httpxEnvironment{
"extras": "",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | httpx>=0.27 | runtime |
mcpEnvironment{
"extras": "cli",
"marker": null,
"requires_python": ">=3.10",
"evaluation": "NOT_EVALUATED"
} | mcp[cli]>=1.0 | runtime |
bdist_wheel · 13.43 KB · Python py3
sdist · 20.53 KB · Python source
Shared repository data · GitHub
Public sponsor counts have not been collected. These signals belong to the repository owner.
github · 1 observations shown. Missing days are unknown.
| Date / source period | Value | Observed at |
|---|---|---|
| 2026-10-21 | 0 | 2026-10-21T21:13:04.4632701Z |
Observed since 20 Oct, 22:53 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:e019f7ef9231bd428f271738bd25eb59a0ad102db45a4b0c186df1b6d681debf