x402 Payment Protocol
The first multi-chain, multi-asset x402 facilitator. Accept BTC, ETH, SOL, POL, BCH, USDC, Lightning, and card payments — all inline with HTTP requests.
How It Works
Client Requests
Client hits your API endpoint
402 + Options
Server returns all accepted payment methods
Client Pays
Client picks BTC, ETH, Lightning, card...
Access Granted
Payment verified, resource served
Fees
CoinPayPortal charges a small commission on each x402 payment, deducted before forwarding to the merchant. The same fee structure applies to all CoinPayPortal payment methods.
| Plan | Commission | Merchant Receives | Price |
|---|---|---|---|
| Starter (Free) | 1.0% | 99.0% | $0/mo |
| Professional | 0.5% | 99.5% | $49/mo |
Network fees (gas, miner fees) are separate and vary by chain. Lightning payments have near-zero network fees. No hidden fees — what you see is what you pay.
How Clients Pay
When a client (browser, AI agent, or bot) hits an x402-protected endpoint, they get back a 402 response with all accepted payment methods. Here's what happens:
1. Client receives payment options
The 402 response body contains an accepts array — one entry per payment method the merchant supports:
HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"network": "bitcoin",
"asset": "BTC",
"maxAmountRequired": "769", // satoshis
"payTo": "bc1qMerchant...",
"extra": { "label": "Bitcoin" }
},
{
"scheme": "exact",
"network": "base",
"asset": "0xA0b8...eB48", // USDC contract
"maxAmountRequired": "5000000", // 6 decimals = $5.00
"payTo": "0xMerchant...",
"extra": { "label": "USDC on Base", "chainId": 8453 }
},
{
"scheme": "exact",
"network": "lightning",
"asset": "BTC",
"maxAmountRequired": "769",
"payTo": "lno1Merchant...", // BOLT12 offer
"extra": { "label": "Lightning" }
}
// ... more methods
],
"error": "Payment required"
}2. Client picks a method and creates payment proof
The client chooses a payment method from the accepts array, then:
- USDC (EVM chains): Sign an EIP-712 typed message authorizing a
transferFrom— no on-chain tx yet, just a signature - Bitcoin/BCH: Broadcast a transaction to the merchant's address, include the txid as proof
- Lightning: Pay the BOLT12 offer, include the preimage as proof
- Solana: Sign and broadcast a transfer, include the signature
- Stripe: Complete card checkout, include the payment intent ID
3. Client retries the request with payment proof
The payment proof goes in the X-PAYMENT header as a base64-encoded JSON payload:
GET /api/premium HTTP/1.1
X-PAYMENT: eyJzY2hlbWUiOiJleGFjdCIsIm5ldHdvcmsiOiJiYXNlIiwiYXNzZXQiOiIweEEwYjg2OTkx...
// Decoded X-PAYMENT payload:
{
"scheme": "exact",
"network": "base",
"asset": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"payload": {
"signature": "0xabc123...", // EIP-712 sig (USDC)
"authorization": {
"from": "0xBuyerAddress...",
"to": "0xMerchantAddress...",
"value": "5000000",
"validAfter": 0,
"validBefore": 1739980800, // expiry timestamp
"nonce": "0xUniqueNonce..."
}
}
}4. Server verifies and serves content
The middleware sends the proof to CoinPayPortal's facilitator (/api/x402/verify) which validates the signature, checks expiry, prevents replay attacks, and optionally settles on-chain. If valid → content is served. If invalid → another 402.
Client Libraries
For automated clients (AI agents, bots), use a library that handles the 402 → pay → retry loop:
import { x402fetch } from '@profullstack/coinpay';
// Wraps fetch() — automatically handles 402 responses
const response = await x402fetch('https://api.example.com/premium', {
paymentMethods: {
// Provide wallet/signer for chains you want to pay with
base: { signer: wallet }, // EVM wallet (ethers/viem)
lightning: { macaroon, host }, // LND credentials
bitcoin: { wif: 'privateKey...' }, // BTC wallet
},
preferredMethod: 'usdc_base', // optional: try this first
});
const data = await response.json();Quick Setup
- Install the SDK:
npm install @profullstack/coinpay - Get your API key from Business Settings
- Configure wallet addresses for each chain you want to accept
- Add the x402 middleware — set a USD price and let the buyer choose their chain
- Test:
coinpay x402 test --url http://localhost:3000/api/premium
Integration Code
import { createX402Middleware } from '@profullstack/coinpay';
const x402 = createX402Middleware({
apiKey: 'YOUR_API_KEY',
payTo: {
bitcoin: 'bc1qYourBtcAddress',
ethereum: '0xYourEvmAddress',
polygon: '0xYourEvmAddress',
solana: 'YourSolanaAddress',
lightning: 'lno1YourBolt12Offer',
stripe: 'acct_YourStripeId',
'bitcoin-cash': 'bitcoincash:qYourBchAddress',
base: '0xYourEvmAddress',
},
rates: { BTC: 65000, ETH: 3500, SOL: 150, POL: 0.50, BCH: 350 },
});
// Charge $5 — buyer picks their chain/asset
app.get('/api/premium', x402({ amountUsd: 5.00 }), (req, res) => {
res.json({ data: 'premium content', paidWith: req.x402Payment });
});Active x402 Endpoints
Endpoints are tracked automatically when payment verifications come through the facilitator.
| Endpoint | Methods | Price | Payments |
|---|---|---|---|
| No x402 endpoints detected yet. Set up the middleware to get started. | |||
x402 Payment History
| Date | From | Amount | Method | Status | Tx |
|---|---|---|---|---|---|
| No x402 payments yet. | |||||
Supported Payment Methods
| Method | Asset | Network | Type | Key |
|---|---|---|---|---|
| Bitcoin | BTC | bitcoin | Native | btc |
| Bitcoin Cash | BCH | bitcoin-cash | Native | bch |
| Ethereum | ETH | ethereum | Native | eth |
| Polygon | POL | polygon | Native | pol |
| Solana | SOL | solana | Native | sol |
| USDC on Ethereum | USDC | ethereum | Stablecoin | usdc_eth |
| USDC on Polygon | USDC | polygon | Stablecoin | usdc_polygon |
| USDC on Solana | USDC | solana | Stablecoin | usdc_solana |
| USDC on Base | USDC | base | Stablecoin | usdc_base |
| Lightning | BTC | lightning | Lightning | lightning |
| Card (Stripe) | USD | stripe | Fiat | stripe |