Concepts

x402 Protocol

How AI agents pay for API calls with USDC-SPL on Solana using HTTP 402

The x402 protocol is a payment-in-HTTP mechanism built on top of the HTTP 402 Payment Required status code. When a client sends a request without payment, the server responds with 402 and a structured description of what it costs and how to pay. The client pays, then retries.

Solvela uses x402 to enable AI agents to pay for LLM API calls with USDC-SPL on Solana, without API keys or accounts.

Request flow

Agent sends request without payment

The agent sends a normal POST /v1/chat/completions request with no payment-signature header.

Gateway returns 402

The gateway computes the cost for the requested model, then returns HTTP 402 with a PaymentRequired JSON body describing the cost and accepted payment methods.

Agent reads cost and builds a transaction

The agent parses the 402 body, reads the amount (atomic USDC) and pay_to (recipient wallet), and builds a signed Solana USDC-SPL transfer transaction.

Agent encodes the PaymentPayload

The signed transaction and metadata are wrapped in a PaymentPayload struct, serialized to JSON, and base64-encoded.

Agent retries with the payment header

The same request is resent with the payment-signature: <base64> header.

Gateway verifies and proxies

The gateway decodes the header, checks replay protection, verifies the Solana transaction on-chain, then proxies to the LLM provider and returns the response.

The 402 response

When no payment-signature header is present, the gateway responds with HTTP 402. The body uses OpenAI error envelope format — the PaymentRequired JSON is inside error.message as a string.

{
  "error": {
    "message": "<JSON-encoded PaymentRequired>"
  }
}

The decoded PaymentRequired object looks like:

{
  "x402_version": 2,
  "resource": {
    "url": "/v1/chat/completions",
    "method": "POST"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
      "amount": "2625",
      "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "pay_to": "<gateway-recipient-wallet>",
      "max_timeout_seconds": 300
    },
    {
      "scheme": "escrow",
      "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
      "amount": "2625",
      "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "pay_to": "<gateway-recipient-wallet>",
      "max_timeout_seconds": 300,
      "escrow_program_id": "9neDHouXgEgHZDde5SpmqqEZ9Uv35hFcjtFEPxomtHLU"
    }
  ],
  "cost_breakdown": {
    "provider_cost": "0.002500",
    "platform_fee": "0.000125",
    "total": "0.002625",
    "currency": "USDC",
    "fee_percent": 5
  },
  "error": "Payment required"
}

Fields

FieldDescription
x402_versionProtocol version. Currently 2.
resource.urlThe endpoint path that requires payment.
resource.methodAlways POST for chat completions.
acceptsArray of accepted payment methods. The agent picks one.
accepts[].scheme"exact" (direct transfer) or "escrow" (on-chain escrow).
accepts[].networkSolana mainnet: solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp.
accepts[].amountCost in atomic USDC units (6 decimals). 2625 = $0.002625.
accepts[].assetUSDC-SPL mint: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v.
accepts[].pay_toGateway recipient wallet (base58).
accepts[].max_timeout_secondsHow long the payment authorization is valid.
accepts[].escrow_program_idOnly present for scheme: "escrow". The deployed Anchor program.
cost_breakdownHuman-readable cost breakdown.

Payment payload format

After building and signing a transaction, wrap it in a PaymentPayload and send it as the payment-signature header:

{
  "x402_version": 2,
  "resource": {
    "url": "/v1/chat/completions",
    "method": "POST"
  },
  "accepted": {
    "scheme": "exact",
    "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
    "amount": "2625",
    "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    "pay_to": "<gateway-recipient-wallet>",
    "max_timeout_seconds": 300
  },
  "payload": {
    "transaction": "<base64-encoded-signed-solana-versioned-tx>"
  }
}

For escrow payments, the payload field uses a different shape:

{
  "payload": {
    "deposit_tx": "<base64-encoded-signed-deposit-tx>",
    "service_id": "<base64-encoded-32-byte-service-id>",
    "agent_pubkey": "<base58-agent-wallet-pubkey>"
  }
}

The entire PaymentPayload object is JSON-serialized and base64-encoded before being placed in the payment-signature header.

Payment schemes

Exact (direct transfer)

The agent sends a USDC-SPL transfer transaction to the gateway's recipient wallet for the exact amount specified. The gateway verifies the transaction on Solana mainnet before serving the request.

Use when: You want simplicity and don't need refund guarantees.

Escrow (trustless on-chain)

The agent deposits USDC into a PDA vault controlled by the Solvela Anchor program (9neDHouXgEgHZDde5SpmqqEZ9Uv35hFcjtFEPxomtHLU). The gateway claims the actual cost from the vault after the request completes. If the gateway fails to claim within the timeout, the agent can reclaim their deposit.

PDA seeds: [b"escrow", agent_pubkey_bytes, service_id_bytes]

Use when: You want trustless guarantees — the gateway can only claim what it actually earned.

See Escrow System for full details.

Security

Replay protection

Every transaction signature is tracked in Redis (or an in-memory LRU with TTL when Redis is unavailable). Submitting the same signed transaction twice returns 402 Invalid Payment.

Amount validation

The gateway recomputes the expected cost server-side and rejects any payment where client_amount < expected_amount. The agent cannot underpay.

Asset and network validation

The gateway validates:

  • accepted.network must be solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
  • accepted.asset must be the USDC-SPL mint
  • accepted.pay_to must match the gateway's configured recipient wallet

Resource binding

The resource.url in the payload is validated against the actual endpoint. A payment for /v1/chat/completions cannot be used on any other endpoint.

Warning

Transactions have a max_timeout_seconds window (default 300 seconds). Build and submit your payment within this window to avoid rejection.