xAPGX Protocol Agent Payment GatewayTESTNET · NO REAL FUNDS

Integration guide

Integrate institutional agent payments

The configured Facilitator flow supports exact Base USDC payments authorized with EIP-3009.

Institutional Facilitator flow

  1. At startup, call GET /supported and select one advertised capability combination.
  2. The merchant returns an x402 requirement; the enterprise wallet creates the EIP-712 authorization outside XAPG.
  3. Send the complete signed payload and unchanged merchant requirements to POST /verify.
  4. After cryptographic verification succeeds, apply your own institutional policies.
  5. Only an approved, unchanged request is sent to POST /settle.
Current configured contract: x402 v2 · exact · Base · USDC · EIP-3009. Never infer a capability absent from GET /supported.

Credential and signing boundary

Institutional backends use a separately issued xapg_inst_… key. The verify and settle scopes are granted separately.

The enterprise wallet owns the signing key; XAPG validates only the signed payload.

Agent apg_… keys and institution xapg_inst_… keys are mutually isolated.

Manage institution API keys

Discover configured capabilities

GEThttps://xapg.io/supported
curl https://xapg.io/supported \
  -H 'X-API-Key: xapg_inst_…'

Match kinds, assets, and extensions[].adapters by network before constructing a payment.

{
  "kinds": [
    { "x402Version": 2, "scheme": "exact", "network": "eip155:CHAIN_ID" }
  ],
  "extensions": [{
    "name": "xapg-payment-adapters",
    "version": "1",
    "adapters": [{
      "id": "eip-3009",
      "network": "eip155:CHAIN_ID",
      "asset": "0x…",
      "settlementSpenders": ["0x…"]
    }]
  }],
  "signers": { "eip155:*": ["0x…"] },
  "assets": [{
    "network": "eip155:CHAIN_ID",
    "address": "0x…",
    "symbol": "USDC",
    "decimals": 6,
    "protocols": ["x402"]
  }]
}

Reject unsupported combinations locally and do not hard-code settlement wallet addresses.

EIP-3009 Facilitator request

POST /verify and POST /settle accept the same object. paymentPayload.accepted must exactly match paymentRequirements.

{
  "x402Version": 2,
  "paymentPayload": {
    "x402Version": 2,
    "resource": {
      "url": "https://merchant.example/resource",
      "description": "Order description",
      "mimeType": "application/json"
    },
    "accepted": {
      "scheme": "exact",
      "network": "eip155:CHAIN_ID",
      "amount": "10000",
      "asset": "0x…USDC from /supported…",
      "payTo": "0x…beneficiary…",
      "maxTimeoutSeconds": 120,
      "extra": { "name": "USDC", "version": "2", "protocol": "eip-3009" }
    },
    "payload": {
      "signature": "0x…EIP-712 signature…",
      "authorization": {
        "from": "0x…payer…",
        "to": "0x…same beneficiary…",
        "value": "10000",
        "validAfter": "…unix seconds…",
        "validBefore": "…unix seconds…",
        "nonce": "0x…32 bytes…"
      }
    }
  },
  "paymentRequirements": {
    "scheme": "exact",
    "network": "eip155:CHAIN_ID",
    "amount": "10000",
    "asset": "0x…USDC from /supported…",
    "payTo": "0x…beneficiary…",
    "maxTimeoutSeconds": 120,
    "extra": { "name": "USDC", "version": "2", "protocol": "eip-3009" }
  }
}
For six-decimal USDC, 10000 base units means 0.01 USDC.

Verify without settlement

POSThttps://xapg.io/verify
curl -X POST https://xapg.io/verify \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: xapg_inst_…' \
  --data-binary @signed-payment.json
{ "isValid": true, "payer": "0x…" }

Verification checks protocol invariants and simulates settlement. It submits no transaction.

Common invalidReason values include unsupported_payment_protocol, recipient_mismatch, signer_mismatch, authorization_expired, insufficient_funds, nonce_already_used, and simulation_failed.

Execute settlement

POSThttps://xapg.io/settle
curl -X POST https://xapg.io/settle \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: xapg_inst_…' \
  --data-binary @signed-payment.json
{
  "success": true,
  "network": "eip155:CHAIN_ID",
  "payer": "0x…",
  "transaction": "0x…"
}

Treat success: true plus a valid transaction as completion. Do not retry blindly.

Persist the request, policy result, payer, network, transaction, and final chain receipt.

MPP is a separate resource flow

MPP does not use the institutional /supported → /verify → /settle client sequence. Its middleware uses the shared PaymentService settlement path.

GEThttps://xapg.io/mpp/resource
The configured MPP endpoint is testnet-only.

Testnet-only Base Sepolia EIP-3009 Python example

This PoC is specific to Base Sepolia EIP-3009 and never reads a wallet private key.

Create signed EIP-3009 test request

export XAPG_FACILITATOR_API_KEY='xapg_inst_…'
export XAPG_ALLOWED_PAY_TO='0x…approved beneficiary…'

python3 scripts/test_xapg_api.py

python3 scripts/test_xapg_api.py \
  --request-file signed-payment.json

python3 scripts/test_xapg_api.py \
  --request-file signed-payment.json \
  --settle \
  --confirm-settlement BASE_SEPOLIA \
  --receipt-file xapg-settlement-receipt.json
The script fails closed and records completion only after a successful Base Sepolia receipt.

Separate Agent product: Remote MCP

Remote MCP is a separate user-scoped Agent product with browser OAuth.

POSThttps://xapg.io/v1/mcp
codex mcp add xapg --url https://xapg.io/v1/mcp
codex mcp login xapg

claude mcp add --transport http xapg https://xapg.io/v1/mcp --scope user

Pair a wallet and confirm every exact x402 payment in the paired wallet.

payment_capabilities    → read configured Base capability, policy, and wallet session
list_payment_recipients → read approved recipient IDs
request_test_payment    → request by recipientId, exact amount, and reason
x402_fetch              → request an external merchant x402 resource
x402_status             → check durable approval and wallet-request status
x402_resume             → continue only when readyToResume is true
A started wallet request is not proof of payment. Report completion only after settlement is confirmed.

Permit2 · Coming soon

The adapter architecture and internal tests cover a Permit2 path, but Permit2 is not part of the current public integration contract.

Coming soon. Only assets explicitly returned by GET /supported are supported.