Build agent payment flows with AgentPay
Use AgentPay to give an AI agent a wallet, apply spending policy, create a payment, and return an auditable receipt to your runtime. This guide is written for developers building server-side agent tools.
Overview
AgentPay exposes a REST API for agent identity, wallet state, payment creation, policy checks, and webhook delivery. The simplest integration is a server-side tool registry: the model asks to perform a payment action, your runtime validates the request, then your server calls AgentPay.
Before you begin
Start the local sandbox with PostgreSQL, then set a base URL for the request examples.
npm install
npm run db:up
npm run migrate
npm run seed
npm run dev
export AGENTPAY_BASE_URL="http://localhost:3100"The server exposes human-friendly demo pages and JSON API routes from the same process. For a hosted public alpha, production startup requires strong secrets, an explicit proxy depth, hosted HTTPS origins, and sandbox-only demo mode.
NODE_ENV=production
JWT_SECRET="replace-with-at-least-32-random-characters"
DATABASE_URL="postgresql://user:pass@db-host:5432/agentpay"
TRUST_PROXY_HOPS=1
PUBLIC_DEMO_MODE=true
PUBLIC_DEMO_SANDBOX_ONLY=true
PUBLIC_DEMO_ALLOWED_ORIGINS="https://your-demo-host.example"
PUBLIC_DEMO_ADMIN_TOKEN="replace-with-at-least-32-random-characters"Core resources
These are the objects you use in the first payment workflow.
AgentRuntime identityOwns API credentials, policy context, wallet records, and transaction history.WalletSpendable balanceHolds sandbox funds and provides the from_wallet_id used in payment requests.PaymentLedger eventMoves value, evaluates policy, records status, and emits webhook events.Quickstart
The fastest proof path is three calls: create an agent, fund the wallet, and make one payment. These examples use curl for readability.
| Field | Required | Description |
|---|---|---|
name | Yes | Human-readable agent name. |
operator | No | Your team, app, or tenant identifier. |
curl -X POST "$AGENTPAY_BASE_URL/v1/agents" \
-H "Content-Type: application/json" \
-d '{
"name": "ResearchOpsAgent",
"operator": "acme"
}'{
"id": "agent_...",
"api_key": "pk_test_...",
"wallet_id": "wallet_...",
"secret_key": "sk_test_..."
}curl -X POST "$AGENTPAY_BASE_URL/v1/wallets/$WALLET_ID/fund" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": 100,
"source": "test_faucet"
}'| Field | Required | Description |
|---|---|---|
from_wallet_id | Yes | The payer wallet owned by the authenticated agent. |
to_wallet_id or to_external | Yes | A sandbox wallet recipient or an external payee label. |
amount | Yes | Payment amount before fee. |
rail | No | Defaults to internal. Public demo mode can restrict allowed rails. |
idempotency_key | No | Use for retry-safe agent workflows. |
curl -X POST "$AGENTPAY_BASE_URL/v1/payments" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from_wallet_id": "'$WALLET_ID'",
"to_external": "merchant:demo",
"amount": 5,
"currency": "USD",
"rail": "internal",
"description": "Agent tool purchase",
"idempotency_key": "tool-call-001"
}'{
"id": "tx_...",
"amount": 5,
"fee": 0.02,
"total_debited": 5.02,
"currency": "USD",
"rail": "internal",
"status": "completed"
}AI Platform Support
AgentPay integrates with every major AI framework. Full setup guides are on the Integrations page.
| Platform | Method | Endpoint / Package | Guide |
|---|---|---|---|
|
|
MCP | npx agentpay-mcp |
Setup → |
|
|
Function Calling | GET /ai/tools?format=openai |
Setup → |
|
|
Function Calling | GET /ai/tools?format=gemini |
Setup → |
|
|
MCP | npx agentpay-mcp |
Setup → |
|
|
OpenAPI v2 | GET /.well-known/ai-plugin.json |
Setup → |
|
|
Tool Schema | GET /ai/tools?format=langchain |
Setup → |
|
|
Function Calling | GET /ai/tools?format=autogen |
Setup → |
|
|
Function Calling | GET /ai/tools?format=openai |
Setup → |
|
|
OpenAPI | GET /openapi/spec.json |
Setup → |
|
|
Native Python | pip install agentpay-nemo |
Setup → |
|
|
MCP + Skill | clawhub install agentpay |
Setup → |
|
|
MCP | npx agentpay-mcp |
Setup → |
Retrieve balances and payments
Read endpoints are safe to expose through your server-side runtime after you enforce tenant and agent authorization.
curl "$AGENTPAY_BASE_URL/v1/wallets/$WALLET_ID/balance" \
-H "Authorization: Bearer $AGENTPAY_API_KEY"curl "$AGENTPAY_BASE_URL/v1/payments/$PAYMENT_ID" \
-H "Authorization: Bearer $AGENTPAY_API_KEY"Listen for webhooks
Register a webhook endpoint to receive signed payment lifecycle events. Delivery rows are persisted and retried by the dispatcher.
curl -X POST "$AGENTPAY_BASE_URL/v1/webhooks" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/agentpay/webhooks",
"events": ["payment.completed", "payment.refunded"]
}'| Event | When it fires |
|---|---|
payment.initiated | A non-internal payment request is recorded. |
payment.completed | An internal payment completes and posts to the ledger. |
payment.refunded | A completed payment is refunded. |
Service Marketplace
The service registry lets agents publish callable services and lets consumer agents discover, authorize, and pay for them via the x402 payment token flow. A trust_score (0–100) tracks provider reliability based on settlement and dispute history — it is cached per-service for fast discovery reads.
ServiceCallable endpointA provider-registered endpoint with a price, category, and optional SLA contract. Results are cached 5 s for list queries.AuthorizationPayment reservationLocks consumer funds and returns a signed payment token valid for one call. Passed to the provider in X-Payment-Token.trust_scoreReputation signalInteger 0–100 updated after each settled or disputed call. Debounced via background job to avoid UPDATE storms.| Query param | Required | Description |
|---|---|---|
category | No | Filter by category label (e.g. data, compute, llm). |
verified | No | Pass true to return only operator-verified providers. |
limit | No | Page size, max 100. Default 20. |
offset | No | Pagination offset. Default 0. |
curl "$AGENTPAY_BASE_URL/v1/services?category=data&verified=true" \
-H "Authorization: Bearer $AGENTPAY_API_KEY"{
"services": [
{
"id": "svc_...",
"name": "MarketDataFeed",
"slug": "marketdatafeed",
"price_per_call": 0.005,
"currency": "USD",
"category": "data",
"trust_score": 84,
"verified": true,
"status": "active"
}
],
"total": 1
}| Field | Required | Description |
|---|---|---|
from_wallet_id | Yes | Consumer wallet to debit on settlement. |
max_amount | No | Override the service price ceiling for this single call. |
curl -X POST "$AGENTPAY_BASE_URL/v1/services/$SERVICE_ID/authorize" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"from_wallet_id": "'$WALLET_ID'"}'{
"token": "x402_tok_...",
"token_id": "tokid_...",
"expires_at": "2026-05-08T13:05:00Z",
"service_id": "svc_...",
"reserved_amount": 0.005
}| Field | Required | Description |
|---|---|---|
name | Yes | Unique display name for the service. |
description | No | Short description shown to consumers in the marketplace. |
price_per_call | Yes | Amount charged per verified call in currency. |
currency | No | Defaults to USD. |
category | No | Discovery tag, e.g. data, compute, llm. |
endpoint_url | No | The URL consumers call after receiving a payment token. |
curl -X POST "$AGENTPAY_BASE_URL/v1/services" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "WeatherAPI",
"description": "Real-time weather data per query",
"price_per_call": 0.002,
"currency": "USD",
"category": "data",
"endpoint_url": "https://api.example.com/weather"
}'{
"id": "svc_...",
"slug": "weatherapi",
"status": "active",
"trust_score": 50
}Disputes
Any party to a completed payment can open a dispute within the allowed window. Operators review evidence and resolve — refunding the consumer or denying the claim. A withdrawal option lets the opener drop a dispute before it is reviewed.
open → under_review → resolved_refunded | resolved_denied | withdrawnresolved_refunded outcome returns the payment principal. The transaction fee is retained by the platform.| Field | Required | Description |
|---|---|---|
payment_id | Yes | The id of the transaction to dispute. |
reason | Yes | Reason code, e.g. service_not_delivered, incorrect_amount. |
description | No | Free-text narrative for the reviewer. |
curl -X POST "$AGENTPAY_BASE_URL/v1/disputes" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"payment_id": "'$PAYMENT_ID'",
"reason": "service_not_delivered",
"description": "Provider returned 503 after token was consumed"
}'{
"id": "disp_...",
"status": "open",
"payment_id": "tx_...",
"reason": "service_not_delivered",
"created_at": "2026-05-08T12:00:00Z"
}curl "$AGENTPAY_BASE_URL/v1/disputes?status=open" \
-H "Authorization: Bearer $AGENTPAY_API_KEY"| Field | Required | Description |
|---|---|---|
type | Yes | Evidence category, e.g. log_excerpt, screenshot, api_response. |
content | Yes | Text content or base64-encoded data. |
curl -X POST "$AGENTPAY_BASE_URL/v1/disputes/$DISPUTE_ID/evidence" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "log_excerpt",
"content": "HTTP 503 at 2026-05-08T11:59:01Z — no response body"
}'Payouts
Move funds from an agent wallet to an external destination. Payouts are asynchronous — poll GET /v1/payouts/:id or subscribe to payout.completed webhook events to track settlement. Three destination types are supported.
| Field | Required | Description |
|---|---|---|
from_wallet_id | Yes | Source wallet owned by the authenticated agent. |
amount | Yes | Amount to withdraw in the wallet currency. |
destination_type | Yes | bank (ACH), crypto (on-chain), or stripe (connected account). |
destination | Yes | Type-specific object — see examples below. |
description | No | Memo shown on the settlement statement. |
curl -X POST "$AGENTPAY_BASE_URL/v1/payouts" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from_wallet_id": "'$WALLET_ID'",
"amount": 250.00,
"destination_type": "bank",
"destination": {
"routing_number": "021000021",
"account_number": "9876543210",
"account_type": "checking",
"account_holder": "Acme Corp"
}
}'curl -X POST "$AGENTPAY_BASE_URL/v1/payouts" \
-H "Authorization: Bearer $AGENTPAY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from_wallet_id": "'$WALLET_ID'",
"amount": 50.00,
"destination_type": "crypto",
"destination": {
"address": "0xABCDEF...",
"network": "ethereum"
}
}'{
"id": "payout_...",
"status": "pending",
"amount": 250.00,
"currency": "USD",
"destination_type": "bank",
"estimated_arrival": "2026-05-10",
"created_at": "2026-05-08T12:00:00Z"
}curl "$AGENTPAY_BASE_URL/v1/payouts?status=pending" \
-H "Authorization: Bearer $AGENTPAY_API_KEY"x402 token lifecycle
x402 is the primary agent-to-agent payment protocol on AgentPay. A consumer authorizes a service call, receives a signed payment token, passes it to the provider, and the provider redeems it before delivering. SLA breach detection runs on a per-minute pg-boss job — breached tokens are auto-refunded without operator involvement.
POST /v1/services/:id/authorize — reserves funds and returns a signed token with an expiry.X-Payment-Token header (or payment_token body field) when calling the provider endpoint.POST /v1/x402/verify with the raw token string. AgentPay validates the signature, confirms the reservation, and returns the service metadata.call-started, call-accepted, and call-completed in sequence. These events anchor SLA monitoring and trigger final settlement.call-completed does not arrive within the SLA window, the background job refunds the consumer and marks the token sla_breached.| Endpoint | Actor | Purpose |
|---|---|---|
POST /v1/x402/verify | Provider | Validate and redeem the token before delivering service. |
POST /v1/x402/tokens/:id/call-started | Provider | Mark the call in-flight — starts the SLA clock. |
POST /v1/x402/tokens/:id/call-accepted | Provider | Confirm the request is accepted and processing has begun. |
POST /v1/x402/tokens/:id/call-completed | Provider | Mark the call finished — finalizes settlement, stops SLA clock. |
DELETE /v1/x402/tokens/:id | Consumer | Cancel an unused token and release the reserved funds. |
GET /v1/x402/requirements | Consumer | Check payment requirements for a protected resource URL. |
sla.cleanup pg-boss job runs every minute with singleton deduplication — exactly one node runs the scan at a time across the full cluster.Shared sandbox mode
The public demo sandbox lets a browser host invite external agent runtimes into the same explorer session without exposing long-lived API keys.
/explorer, creates or shares invites, and can perform writes when host-only mutation mode is enabled.x-explorer-access token, then uses that token with the SDK or direct API calls./ops/public-alpha to observe sessions, runtime settings, rate limits, queue depth, and the kill switch.Error handling
Agent runtimes should convert API errors into tool results the model can reason about. Treat policy and balance errors as expected business outcomes, not infrastructure failures.
| Code | Meaning | Runtime behavior |
|---|---|---|
AP-1001 | Wallet, authorization, or balance problem. | Ask for a different wallet, smaller amount, or operator action. |
AP-1002 | Policy denied the transaction. | Return the policy reason to the agent and stop the payment attempt. |
AP-3002 | Agent rate limit exceeded. | Back off and retry after the rate-limit window. |
DEMO_READ_ONLY | Guest browser writes are blocked in public demo mode. | Use the host browser or exchanged runtime token for writes. |
DUPLICATE_DISPUTE | A dispute already exists for this payment. | Fetch the existing dispute from GET /v1/disputes and add evidence instead of opening a new one. |
TOKEN_EXPIRED | The x402 payment token has expired before it was verified. | Ask the consumer to re-authorize the service call and pass a fresh token. |
SETTLEMENT_NOT_CONFIGURED | No settlement connector registered for the selected rail. | Use the internal rail for sandbox testing or configure a production connector for live settlement. |
Production readiness checklist
Before live settlement, treat these as required work items rather than optional polish.
Last reviewed for the local prototype on May 8, 2026.