Agent runtime guide

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.

!
AgentPay is production-demo ready, not real-money production ready. The current implementation is a sandbox and pilot system. Keep API keys server-side, keep public demo mode sandbox-only, and do not route live settlement until the production hardening checklist is complete.

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.

Register or select an agentCreate an AgentPay identity and store the returned API key in your server-side secret store.
Fund a sandbox walletUse the test faucet in local or public demo mode so the agent has spendable balance.
Create a paymentSend a payment request with a wallet, amount, rail, recipient, idempotency key, and optional description.
Inspect the receiptRead the payment back by id or listen for webhook events to update your agent workflow.

Before you begin

Start the local sandbox with PostgreSQL, then set a base URL for the request examples.

Terminal
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.

Hosted demo env
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.

POST/v1/agents
Creates an agent and default wallet
FieldRequiredDescription
nameYesHuman-readable agent name.
operatorNoYour team, app, or tenant identifier.
Request
curl -X POST "$AGENTPAY_BASE_URL/v1/agents" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ResearchOpsAgent",
    "operator": "acme"
  }'
Response shape
{
  "id": "agent_...",
  "api_key": "pk_test_...",
  "wallet_id": "wallet_...",
  "secret_key": "sk_test_..."
}
POST/v1/wallets/:wallet_id/fund
Adds sandbox funds
Request
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"
  }'
POST/v1/payments
Creates a payment and receipt
FieldRequiredDescription
from_wallet_idYesThe payer wallet owned by the authenticated agent.
to_wallet_id or to_externalYesA sandbox wallet recipient or an external payee label.
amountYesPayment amount before fee.
railNoDefaults to internal. Public demo mode can restrict allowed rails.
idempotency_keyNoUse for retry-safe agent workflows.
Request
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"
  }'
Response shape
{
  "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
Claude Claude MCP npx agentpay-mcp Setup →
OpenAI OpenAI Function Calling GET /ai/tools?format=openai Setup →
Gemini Gemini Function Calling GET /ai/tools?format=gemini Setup →
GitHub Copilot GitHub Copilot MCP npx agentpay-mcp Setup →
Copilot Studio Copilot Studio OpenAPI v2 GET /.well-known/ai-plugin.json Setup →
LangChain LangChain Tool Schema GET /ai/tools?format=langchain Setup →
AutoGen AutoGen Function Calling GET /ai/tools?format=autogen Setup →
CrewAI CrewAI Function Calling GET /ai/tools?format=openai Setup →
LlamaIndex LlamaIndex OpenAPI GET /openapi/spec.json Setup →
NeMo Agent Toolkit NeMo Agent Toolkit Native Python pip install agentpay-nemo Setup →
OpenClaw OpenClaw MCP + Skill clawhub install agentpay Setup →
Manus Manus 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.

GET/v1/wallets/:wallet_id/balance
Returns current wallet balance
curl "$AGENTPAY_BASE_URL/v1/wallets/$WALLET_ID/balance" \
  -H "Authorization: Bearer $AGENTPAY_API_KEY"
GET/v1/payments/:payment_id
Fetches payment status and receipt fields
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.

POST/v1/webhooks
Registers a delivery target
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"]
  }'
EventWhen it fires
payment.initiatedA non-internal payment request is recorded.
payment.completedAn internal payment completes and posts to the ledger.
payment.refundedA 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.
GET/v1/services
Lists available services (5 s cache)
Query paramRequiredDescription
categoryNoFilter by category label (e.g. data, compute, llm).
verifiedNoPass true to return only operator-verified providers.
limitNoPage size, max 100. Default 20.
offsetNoPagination offset. Default 0.
Request
curl "$AGENTPAY_BASE_URL/v1/services?category=data&verified=true" \
  -H "Authorization: Bearer $AGENTPAY_API_KEY"
Response shape
{
  "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
}
POST/v1/services/:service_id/authorize
Reserves funds and returns a payment token
FieldRequiredDescription
from_wallet_idYesConsumer wallet to debit on settlement.
max_amountNoOverride the service price ceiling for this single call.
Request
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'"}'
Response shape
{
  "token": "x402_tok_...",
  "token_id": "tokid_...",
  "expires_at": "2026-05-08T13:05:00Z",
  "service_id": "svc_...",
  "reserved_amount": 0.005
}
POST/v1/services
Registers a new service (provider only)
FieldRequiredDescription
nameYesUnique display name for the service.
descriptionNoShort description shown to consumers in the marketplace.
price_per_callYesAmount charged per verified call in currency.
currencyNoDefaults to USD.
categoryNoDiscovery tag, e.g. data, compute, llm.
endpoint_urlNoThe URL consumers call after receiving a payment token.
Request
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"
  }'
Response shape
{
  "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.

Dispute statesopenunder_reviewresolved_refunded | resolved_denied | withdrawn
Fee retentionA resolved_refunded outcome returns the payment principal. The transaction fee is retained by the platform.
POST/v1/disputes
Opens a dispute on a completed payment
FieldRequiredDescription
payment_idYesThe id of the transaction to dispute.
reasonYesReason code, e.g. service_not_delivered, incorrect_amount.
descriptionNoFree-text narrative for the reviewer.
Request
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"
  }'
Response shape
{
  "id": "disp_...",
  "status": "open",
  "payment_id": "tx_...",
  "reason": "service_not_delivered",
  "created_at": "2026-05-08T12:00:00Z"
}
GET/v1/disputes
Lists disputes for the authenticated agent
Request
curl "$AGENTPAY_BASE_URL/v1/disputes?status=open" \
  -H "Authorization: Bearer $AGENTPAY_API_KEY"
POST/v1/disputes/:dispute_id/evidence
Adds evidence to an open or under-review dispute
FieldRequiredDescription
typeYesEvidence category, e.g. log_excerpt, screenshot, api_response.
contentYesText content or base64-encoded data.
Request
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.

POST/v1/payouts
Creates a payout to an external destination
FieldRequiredDescription
from_wallet_idYesSource wallet owned by the authenticated agent.
amountYesAmount to withdraw in the wallet currency.
destination_typeYesbank (ACH), crypto (on-chain), or stripe (connected account).
destinationYesType-specific object — see examples below.
descriptionNoMemo shown on the settlement statement.
Bank ACH
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"
    }
  }'
Crypto (on-chain)
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"
    }
  }'
Response shape
{
  "id": "payout_...",
  "status": "pending",
  "amount": 250.00,
  "currency": "USD",
  "destination_type": "bank",
  "estimated_arrival": "2026-05-10",
  "created_at": "2026-05-08T12:00:00Z"
}
GET/v1/payouts
Lists payouts for the authenticated agent
Request
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.

Consumer: authorizeCall POST /v1/services/:id/authorize — reserves funds and returns a signed token with an expiry.
Consumer → Provider: pass the tokenInclude the token in the X-Payment-Token header (or payment_token body field) when calling the provider endpoint.
Provider: verifyCall POST /v1/x402/verify with the raw token string. AgentPay validates the signature, confirms the reservation, and returns the service metadata.
Provider: lifecycle eventsCall call-started, call-accepted, and call-completed in sequence. These events anchor SLA monitoring and trigger final settlement.
Auto-refund on SLA breachIf call-completed does not arrive within the SLA window, the background job refunds the consumer and marks the token sla_breached.
EndpointActorPurpose
POST /v1/x402/verifyProviderValidate and redeem the token before delivering service.
POST /v1/x402/tokens/:id/call-startedProviderMark the call in-flight — starts the SLA clock.
POST /v1/x402/tokens/:id/call-acceptedProviderConfirm the request is accepted and processing has begun.
POST /v1/x402/tokens/:id/call-completedProviderMark the call finished — finalizes settlement, stops SLA clock.
DELETE /v1/x402/tokens/:idConsumerCancel an unused token and release the reserved funds.
GET /v1/x402/requirementsConsumerCheck payment requirements for a protected resource URL.
SLA enforcementSLA contracts are attached at service registration. The sla.cleanup pg-boss job runs every minute with singleton deduplication — exactly one node runs the scan at a time across the full cluster.
Token expiryTokens expire after a short TTL (default 5 minutes). Expired tokens cannot be verified, and the reserved amount is automatically returned to the consumer wallet on expiry.

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.

Host browserOpens /explorer, creates or shares invites, and can perform writes when host-only mutation mode is enabled.
Guest runtimeExchanges an invite for a short-lived x-explorer-access token, then uses that token with the SDK or direct API calls.
Ops panelUse /ops/public-alpha to observe sessions, runtime settings, rate limits, queue depth, and the kill switch.
No real moneyKeep public demo mode sandbox-only and restrict rails, funding caps, payment caps, session TTLs, and guest writes.

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.

CodeMeaningRuntime behavior
AP-1001Wallet, authorization, or balance problem.Ask for a different wallet, smaller amount, or operator action.
AP-1002Policy denied the transaction.Return the policy reason to the agent and stop the payment attempt.
AP-3002Agent rate limit exceeded.Back off and retry after the rate-limit window.
DEMO_READ_ONLYGuest browser writes are blocked in public demo mode.Use the host browser or exchanged runtime token for writes.
DUPLICATE_DISPUTEA dispute already exists for this payment.Fetch the existing dispute from GET /v1/disputes and add evidence instead of opening a new one.
TOKEN_EXPIREDThe 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_CONFIGUREDNo 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.

Settlement connectorChoose one production rail and implement authorization, submission, settlement, failure, refund, and reconciliation end to end.
Transaction lifecycleAdd explicit states for pending, authorized, submitted, settling, completed, failed, refunded, and expired flows.
Secrets and authRequire production configuration for JWT secrets, database settings, admin tokens, and key rotation.
OperationsAdd distributed rate limits, metrics, traces, alerting, backup/restore procedures, and incident runbooks.

Last reviewed for the local prototype on May 8, 2026.