x402: HTTP-Native Payments

How the x402 protocol turns HTTP 402 into a concrete payment flow for AI agents.

HTTP status code 402 ("Payment Required") has existed since 1997. The x402 protocol finally gives it a concrete implementation: agents pay per-request in USDC, with no accounts, API keys, or invoicing.

The Flow

  1. Agent sends GET /api/data to a merchant
  2. Merchant returns 402 Payment Required with a JSON body:
{
  "x402Version": 2,
  "accepts": [
    {
      "scheme": "exact",
      "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",
      "amount": "10000",
      "resource": "https://merchant.com/api/data",
      "payTo": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU",
      "extra": {
        "name": "Premium weather data",
        "facilitatorUrl": "https://facilitator.pincerpay.com"
      }
    }
  ]
}
  1. Agent signs a USDC transfer and POSTs it to the facilitator's /v1/settle endpoint
  2. Facilitator verifies the transaction, broadcasts it on-chain
  3. Agent retries the original request with the receipt in the X-PAYMENT header
  4. Merchant verifies the receipt and serves the resource

See this flow animated step by step in the interactive demo.

Why This Matters

  • No API keys to manage -- agents pay per-request, no account creation needed
  • No rate limits -- every request that pays gets served
  • No invoicing -- settlement is instant, on-chain, final
  • Any HTTP endpoint -- works with REST, GraphQL, file downloads, anything over HTTP

The Facilitator

The PincerPay Facilitator is the intermediary that verifies and broadcasts transactions. It ensures merchants don't need to run their own on-chain infrastructure.

  1. Verify -- checks that the signed transaction matches the payment requirements (amount, recipient, chain)
  2. Broadcast -- submits the transaction on-chain
  3. Confirm -- monitors confirmation status and notifies merchants via webhooks

Merchants interact with the facilitator through the @pincerpay/merchant middleware. Agents interact through @pincerpay/agent. Neither needs direct facilitator API knowledge for basic usage. See the API Reference for direct integration.

Describing x402 in OpenAPI

If you publish an OpenAPI spec for an x402-paywalled API, model the payment receipt as an apiKey security scheme carried in the X-PAYMENT request header. This is the canonical representation; every downstream spec should describe it the same way so tools and agents recognize it.

The exact wire contract set by the PincerPay middleware:

  • Payment receipt header (request): X-PAYMENT (the middleware also accepts payment-signature for compatibility, but X-PAYMENT is canonical).
  • Unpaid response: HTTP 402 with the requirements JSON in the body and a base64-encoded copy in the payment-required response header.
  • Settled response: the original 2xx, plus a base64-encoded receipt in the payment-response response header.
  • Price: advertised in the 402 body at accepts[].amount, as USDC base units (6 decimals - "10000" = $0.01), per scheme/network/asset/payTo. There is no X-PRICE-USD header; price is not a header at all.
components:
  securitySchemes:
    x402Payment:
      type: apiKey
      in: header
      name: X-PAYMENT
      description: >
        Base64-encoded x402 payment payload. Obtain the requirements by
        calling the endpoint without this header and reading the 402 response
        body (`accepts[]`), then settle and retry with the receipt here.
  responses:
    PaymentRequired:
      description: Payment required (x402). Body lists accepted payment options.
      headers:
        payment-required:
          schema: { type: string }
          description: Base64-encoded copy of the requirements body.
      content:
        application/json:
          schema:
            type: object
            properties:
              x402Version: { type: integer, example: 2 }
              accepts:
                type: array
                items:
                  type: object
                  properties:
                    scheme:  { type: string, example: exact }
                    network: { type: string, example: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" }
                    amount:  { type: string, description: "USDC base units (6 decimals)", example: "10000" }
                    asset:   { type: string, description: "USDC token address on the network" }
                    payTo:   { type: string }

paths:
  /api/data:
    get:
      security:
        - x402Payment: []
      # Recommended vendor extension for static price advertisement.
      # The authoritative price is always the live 402 `accepts[].amount`.
      x-pincerpay-price:
        usdc: "0.01"          # human-readable USDC
        chains: ["solana"]    # chain shorthands that can settle
      responses:
        "200": { description: Resource delivered after payment }
        "402": { $ref: "#/components/responses/PaymentRequired" }

Prefer x-pincerpay-price (human-readable USDC + chains, mirroring PincerPayConfig["routes"]) over an ad-hoc x-price-usd, and treat it as advisory: the live 402 accepts[].amount (base units) is the source of truth.