A simple, HTTP-native protocol for on-chain payments. x402 makes it trivial for web services to accept low-fee, fast blockchain payments with minimal integration.
"One line of server code to accept digital dollars — no fee, ~2s settlement, $0.001 minimum payment."
Quick example (Express):
import { paymentMiddleware } from 'x402-payment-system';
app.use(
paymentMiddleware({
payTo: "0xYourAddress",
prices: { "/your-endpoint": "$0.01" },
networkId: "56" // BNB Chain
})
);See examples/typescript/servers/express.ts for a complete example.
- TL;DR
- Getting started
- Design & philosophy
- Protocol overview
- Type specifications
- Facilitator HTTP API
- Schemes and networks
- Examples
- Testing
- Contributing
- License
- Purpose: Provide a simple, permissionless, HTTP-native standard for paying web resources using blockchains.
- Integration: 1 line for servers, 1 function for clients.
- Guarantees: Trust-minimizing, chain & token agnostic, gasless for clients & resource servers (via facilitators).
Requirements
- Node.js v24 or higher (for the examples)
Install and run examples (from the repository root):
- Install dependencies and build TypeScript examples
# from repo root
cd examples/typescript
pnpm install; pnpm build- Configure environment variables
cd examples/typescript
copy .env.example .env
# Edit .env and set:
# - PAY_TO: Your payment receiving address
# - PRIVATE_KEY: Client's private key for signing payments
# - RPC_URL: BNB Chain RPC endpoint (optional)- Run an example server
cd examples/typescript
pnpm dev:server
# Or: pnpm server- Run the matching client (in a new terminal)
cd examples/typescript
pnpm dev:client
# Or: pnpm clientYou should see the client successfully request and receive the resource after paying.
x402 was designed to solve shortcomings of existing online payment systems (high fees, friction, and poor programmatic control). Key principles:
- Open standard: no reliance on a single provider.
- HTTP-native: payments are carried alongside normal HTTP requests (no extra handshake outside normal client-server flows).
- Chain & token agnostic: extensible to new chains and signing schemes.
- Trust minimizing: facilitators do not gain unilateral control of funds.
- Easy to use: abstract blockchain complexity into facilitator services so clients and resource servers remain simple.
x402 reuses HTTP status 402 (Payment Required). Typical flow:
- Client requests a resource.
- Resource server responds 402 with a Payment Required object describing accepted payment options.
- Client chooses one payment requirement and constructs a Payment Payload.
- Client repeats the request including
X-PAYMENT: <base64(json)>. - Resource server verifies the payload (locally or via a facilitator
/verify). - If valid, server fulfills the request. Optionally the server settles the payment directly or asks a facilitator to
/settle. - When settled successfully the resource server returns 200 and includes a
X-PAYMENT-RESPONSEheader (base64 JSON) describing settlement details.
This design allows resource servers to trade off immediate response vs stronger settlement guarantees.
Payment Required Response (server -> client)
{
"x402Version": 1,
"accepts": [ /* paymentRequirements */ ],
"error": "" // optional
}paymentRequirements
Payment Payload (sent by client in X-PAYMENT, base64-encoded JSON)
{
"x402Version": 1,
"scheme": "exact",
"network": "1",
"payload": { /* scheme-specific */ }
}A facilitator is an optional 3rd-party that performs verification and on-chain settlement so resource servers don't need node or wallet access.
POST /verify
Request body
{
"x402Version": 1,
"paymentHeader": "<base64-payment-header>",
"paymentRequirements": { /* object from server */ }
}Response
{
"isValid": true,
"invalidReason": null
}POST /settle
Request body same as /verify.
Response
{
"success": true,
"error": null,
"txHash": "0x...",
"networkId": "1"
}GET /supported
Response
{
"kinds": [ { "scheme": "exact", "network": "1" } ]
}Schemes are logical payment methods (for example exact, which transfers a fixed amount). Each (scheme, network) pair defines how the payload is built, verified, and settled. Implementations and facilitators must declare supported pairs.
The repo contains a first-pass spec for exact on EVM chains at specs/schemes/exact/scheme_exact_evm.md.
examples/typescript/servers/express.ts— Express resource server using x402 middleware.examples/typescript/clients/axios— Example client that follows the 402 flow and pays viaX-PAYMENTheader.
Follow the Getting started section above to run them locally.
x402-payment-system/
├── src/ # Core library source
│ ├── types.ts # TypeScript type definitions
│ ├── utils.ts # Utility functions (encoding/decoding)
│ ├── middleware/ # Express middleware
│ │ └── express.ts
│ ├── client/ # Client implementations
│ │ └── axios.ts
│ ├── schemes/ # Payment scheme implementations
│ │ └── exact/
│ │ └── evm.ts
│ └── __tests__/ # Unit tests
├── examples/ # Example implementations
│ └── typescript/
│ ├── servers/ # Server examples
│ └── clients/ # Client examples
├── specs/ # Protocol specifications
│ └── schemes/
└── dist/ # Compiled output
From the repository root:
# Install dependencies
pnpm install
# Run tests
pnpm testThis runs the unit tests for the x402 library.
Contributions are welcome. Please follow these guidelines:
- Read
CONTRIBUTING.md(if present). If not present, open an issue to discuss large changes first. - Keep scheme implementations modular — add new (scheme, network) handlers under
specs/schemes. - Add unit tests for new features and run
pnpm test.
See ROADMAP.md (if present) for longer-term plans and priorities.
- Telegram: https://t.me/Kei4650
- Twitter: https://x.com/kei_4650
This project is provided under the terms of the LICENSE file in the repository root.
{ "scheme": "string", // logical payment scheme (eg. "exact") "network": "string", // chain/network id "maxAmountRequired": "string",// maximum amount in atomic units "resource": "string", // resource URL "description": "string", "mimeType": "string", "outputSchema": null | {}, "payTo": "string", // recipient address "maxTimeoutSeconds": 30, "asset": "string", // e.g. ERC20 contract address where appropriate "extra": null | {} // scheme-specific metadata }