x402 Facilitator

Overview

💡

Try the live demo!

  1. Onboard: Authentication
  2. Integrate: Recipe
  3. Test: Recipe

This overview is written for the merchant — the resource server (seller) that integrates the facilitator into its paywall. You never sign the buyer's transfer or interact with the blockchain; the facilitator does the on-chain work. Your job is three calls:

  1. GET /supported once at startup, to learn the fee-payer address and which (scheme, network) pairs you can charge on.
  2. POST /verify when a buyer presents a payment, to check it's good before you do any work.
  3. POST /settle to broadcast the payment on-chain and get a transaction signature back.

A buyer hits your protected resource, you reply 402 Payment Required with your paymentRequirements, the buyer signs a transfer and sends it back in an PAYMENT-SIGNATURE header. You pass that header into a paymentPayload, then call /verify and /settle with the same (paymentPayload, paymentRequirements) pair.

sequenceDiagram
    participant B as Buyer
    participant M as Merchant
    participant F as Facilitator
    participant S as Solana<br/>(blockchain)

    Note over M,F: At startup
    M->>F: GET /supported
    F-->>M: kinds + feePayer address

    Note over B,S: Per payment
    B->>M: GET /protected-resource
    M-->>B: 402 PAYMENT-REQUIRED + accepts[]

    B->>B: Select paymentDetails<br/>from accepts[]
    B->>B: Create Payment Payload<br/>Sign transaction<br/>(facilitator set as fee-payer)
    B->>M: GET /protected-resource<br/>PAYMENT-SIGNATURE: paymentPayload

    M->>F: POST /verify<br/>(paymentPayload, paymentRequirements)
    F->>F: Screen buyer + merchant
    F->>F: Verify paymentPayload against<br/>paymentRequirements
    F->>S: Simulate transaction
    S-->>F: ok
    F-->>M: Verification Response<br/>isValid true

    M->>M: Perform work to fulfill request
    M->>F: POST /settle<br/>(same payload + requirements)
    F->>F: Re-verify + deduplicate settlements
    F->>S: Submit payment<br/>co-sign as fee-payer + broadcast
    S-->>F: Transaction signature
    F->>S: Wait for blockchain confirmation
    S-->>F: Confirmed
    F-->>M: success: true with transaction hash

    M-->>B: 200 OK + protected resource<br/>PAYMENT-RESPONSE paymentResponse

Conventions for all three endpoints:

  • Send Content-Type: application/json on the two POSTs.
  • A protocol-level rejection (bad payment, sanctioned address, duplicate) is HTTP 200 with { "isValid": false, ... } or { "success": false, ... }. Only a structurally malformed request body is HTTP 400. Don't treat a 200 as success — read the body.
  • Pass an x-request-id header to correlate logs; if you omit it the facilitator generates one and echoes it back on the response.

For background on the solana:… network identifier and the fee-payer address, see CAIP-2 and use the table below:

NetworkCAIP-2 IdentifierFigment Fee Payer
Solana Mainnetsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp93syNmtT1tTd5ZtPwHqzGf6CM7fKhMmArpv4AM4FtyNX
Solana Devnetsolana:EtWTRABZaYq6iMfeYKouRu166VU2xqa12bogRi1wDCdT8ECp8aMrZhF4jX23vxZDUxJjaGkcasKg