Product / Payments

Verify. Settle.
Issue receipts.

The x402 payment protocol turns any HTTP endpoint into a paid resource. Users sign once. The facilitator settles on Base. Receipts enable repeat access without re-payment.

How x402 works

Three-call settlement

01

POST /verify

Validate the EIP-3009 authorization. Checks signature, amount match, nonce freshness, expiry, and gas price. Returns valid: true or a structured error code.

Reference →
02

POST /settle

Execute the on-chain transfer. Facilitator calls transferWithAuthorization on USDC. Returns txHash, payer, and requestId. Gas is paid by the facilitator — not the user.

Reference →
03

Issue receipt

Bind the txHash to a receipt with a TTL. The receipt ID is presented on repeat requests to skip re-settlement. Reduces cost for high-frequency access.

Reference →
Receipt reuse

Pay once. Access many.

After settlement, issue a receipt with a TTL. Present the receipt ID on subsequent requests — the server verifies it without triggering a new settlement.

TTLSet per-receipt. Controls reuse window.
Reuse countTracked. Visible in dashboard and on the receipt object.
RevokeInstant. Revoked receipts return RECEIPT_REVOKED immediately.
Linked endpointReceipt is scoped to a specific resource URL. Cannot be used cross-endpoint.
Receipt verify call
GET /api/v1/receipts/rcpt_01HX.../verify
Authorization: Bearer $P402_API_KEY

# Response (valid):
{
  "valid":      true,
  "reuseCount": 4,
  "expiresAt":  "2025-01-01T01:00:00Z",
  "resource":   "https://your-api.com/endpoint"
}

# Response (expired):
{
  "valid":  false,
  "reason": "RECEIPT_EXPIRED",
  "requestId": "req_..."
}
Error recovery

Common errors and fixes

AMOUNT_MISMATCH
value in authorization ≠ maxAmountRequired
Ensure both fields use atomic USDC units. $1.00 = 1000000.
REPLAY_DETECTED
Nonce already used in a previous settlement
Generate a fresh random bytes32 nonce and re-sign the authorization.
AUTHORIZATION_EXPIRED
validBefore is in the past
Set validBefore to at least 30 seconds in the future at signing time.
GAS_PRICE_TOO_HIGH
Base network gas > configured limit (50 gwei default)
Retry after a few seconds. Gas spikes on Base are typically short.
INVALID_SIGNATURE
EIP-712 signature does not match from address
Verify the EIP-712 domain (chainId: 8453, USDC verifyingContract) and signing wallet.

All errors include a requestId field. Include it when contacting support.

SDK

Drop-in integration

The @p402/sdk handles verify, settle, retry, and receipt reuse automatically. For custom flows, use the REST API directly.

SDK — one line
import { p402Fetch } from '@p402/sdk';

// Drop-in fetch replacement.
// Handles 402 → sign → settle → retry automatically.
const res = await p402Fetch('https://your-api.com/endpoint', {
  wallet: yourWallet,
  maxAmount: 1_000_000n, // $1.00 USDC
});

// res is the successful endpoint response.
// Receipt is stored automatically for reuse.