# 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.

[Run quickstart](/content/developers/quickstart/index.html) [API reference](/content/docs/facilitator/index.html)

## 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 →](/content/docs/facilitator/index.html)

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 →](/content/docs/facilitator/index.html)

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 →](/content/docs/api/index.html)

## 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.

- **TTL**: Set per-receipt. Controls reuse window.
- **Reuse count**: Tracked. Visible in dashboard and on the receipt object.
- **Revoke**: Instant. Revoked receipts return RECEIPT_REVOKED immediately.
- **Linked endpoint**: Receipt 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 docs](/content/docs/sdk/index.html) [Run quickstart](/content/developers/quickstart/index.html)

### 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.
```
