x402 Protocol
Monetize any API with pay-per-request billing using the HTTP 402 Payment Required standard. GullyPay acts as the x402 facilitator, handling payment verification, settlement, and receipt generation.
What is x402?
The x402 protocol extends HTTP with native payment semantics. When a client requests a paid resource, the server responds with 402 Payment Required and includes payment requirements in the X-Payment header. The client pays through a facilitator (GullyPay), receives a receipt, and retries the request with the receipt attached.
This enables AI agents, developers, and applications to pay for API access programmatically without subscriptions or manual billing setup. Note: the facilitator settlement endpoints (POST /x402/pay, /x402/verify, /x402/refund) require a scoped GullyPay API key (Authorization: Bearer rk_… or x-api-key); only GET /x402/status and GET /x402/requirements/:resource are public.
The x402 protocol is an open standard. See the reference implementation at github.com/jinklabs/x402 (opens in a new tab).
How It Works
Step-by-step breakdown:
- Client requests a resource -- a standard HTTP request to any API endpoint.
- Server returns 402 -- the response includes an
X-Paymentheader with pricing, accepted currencies, and the facilitator URL. - Client pays -- the client sends payment details (on-chain transaction hash or card payment) to the GullyPay facilitator.
- Facilitator issues receipt -- after verifying the payment, GullyPay returns a signed receipt token.
- Client retries with receipt -- the original request is retried with the
X-Payment-Receiptheader. - Server verifies receipt -- the server calls GullyPay to verify the receipt is valid, unused, and covers the required amount.
- Facilitator confirms -- returns verification result with payment details.
- Server serves resource -- the paid resource is returned to the client.
Facilitator Endpoints
/x402/statusGet facilitator status, supported schemes, and networks/x402/requirements/:resourceGet payment requirements (returns 402 with X-Payment header)/x402/paySubmit payment and receive a receipt token/x402/verifyVerify a receipt token is valid/x402/refundRequest a refund for a receiptGET /x402/status
Returns the facilitator's capabilities and supported payment networks. Gully Chain Testnet
(gully-chain-testnet, chain id 485590) is listed, with its RPC, explorer and accepted assets under
networks, only while the API runs with GULLY_CHAIN_ENABLED=true. While the flag is off it is not
advertised, endpoints on it cannot be registered and payments on it are rejected.
Supported networks
| Network id | Chain | Chain id | Assets | Notes |
|---|---|---|---|---|
base | Base | 8453 | USDC, USDT | Mainnet |
base-sepolia | Base Sepolia | 84532 | USDC (test) | Testnet |
ethereum | Ethereum | 1 | USDC, USDT | Mainnet |
bsc | BNB Smart Chain | 56 | USDC, USDT | Mainnet |
solana | Solana | none | USDC, USDT | txHash is the base58 signature |
gully-chain-testnet | Gully Chain Testnet (Gully Labs L3) | 485590 | ETH, WETH | Only while GULLY_CHAIN_ENABLED=true |
POST /x402/pay
Submit a payment to receive a receipt token.
| Field | Type | Required | Description |
|---|---|---|---|
resource | string | Yes | URL of the resource being paid for |
txHash | string | Yes | On-chain proof of payment. For EVM networks (base, ethereum, bsc, gully-chain-testnet) this is the 0x-prefixed transaction hash; for solana it is the base58 transaction signature. |
network | string | Yes | Blockchain network (base, ethereum, bsc, solana, or gully-chain-testnet when enabled) |
amount | string | Yes | Payment amount in the smallest unit |
payerAddress | string | Yes | Payer's wallet address |
POST /x402/verify
Verify that a receipt token is valid before serving a resource.
POST /x402/refund
Executes a real on-chain refund: the platform settlement (hot) wallet returns
the paid amount to the original payer's address and the response includes the
actual outbound transaction hash (refundTxHash). The receipt is expired
immediately so it can no longer be redeemed.
Refunds are idempotent — calling refund again for an already-refunded receipt
returns the existing refundTxHash and never sends funds twice.
Refunds move real funds and therefore require the platform settlement hot wallet
to be configured. The refund settles on the same network as the original
payment: EVM networks (Base / Ethereum / BSC) use the secp256k1 hot key
(SETTLEMENT_WALLET_ENCRYPTED_KEY + SETTLEMENT_WALLET_ENCRYPTION_PASSWORD);
Solana uses its own ed25519 hot key (SOLANA_SETTLEMENT_ENCRYPTED_KEY +
SOLANA_SETTLEMENT_ADDRESS + SOLANA_RPC_URL) and returns the base58
transaction signature as refundTxHash. If the hot wallet for that network
is not configured — or the on-chain transfer fails — the refund fails closed
with 503 Service Unavailable and the payment is not marked refunded. No
hash is ever fabricated.
Merchant Payouts
Submit a real on-chain payout from the platform settlement wallet to a merchant's address. Authenticated with the merchant JWT (same as endpoint management).
/x402/merchants/:merchantId/payoutsSend an on-chain payout of a caller-specified amount/x402/merchants/:merchantId/owedAutomated owed-balance report per network + asset/x402/merchants/:merchantId/payouts/owedCompute what's owed for a network + asset and settle it on-chain/x402/merchants/:merchantId/payoutsList a merchant's on-chain payoutsPOST /x402/merchants/:merchantId/payouts
| Field | Type | Required | Description |
|---|---|---|---|
to | string | Yes | Destination address — EVM (0x…) or Solana (base58), matching network |
network | string | Yes | base, ethereum, bsc, or solana |
asset | string | Yes | USDC, USDT, or glUSD |
amount | string | Yes | Integer amount in the asset's on-chain base units (e.g. 1000000 = 1 USDC at 6 decimals) |
Payouts require the settlement hot wallet for the target network (same env as
refunds — EVM secp256k1 key for Base/Ethereum/BSC, ed25519 key for Solana) and
fail closed (503) when that network's wallet is unconfigured. POST /payouts
is a manual primitive that pays the exact amount specified; for automated
settlement use the owed-balance flow below.
Platform fee schedule (per rail)
Every settled payment records a platform fee in the fee ledger, priced per rail so crypto rails are the cheapest option. Amounts are charged in the rail's own minor unit — cents for fiat, the asset's on-chain base units for crypto.
| Rail | Rate | Applied on |
|---|---|---|
| Card | 2.9% + 30¢ | Card/Apple Pay/Google Pay capture (payments.confirm) |
| ACH | 0.8%, capped at $5 | Bank debit |
| Stablecoin | 1.0% | Verified crypto checkout settlement |
| x402 | 1.0% | Verified x402 pay |
| glUSD | 0.5% | glUSD checkout / glUSD-denominated x402 endpoints |
The merchant dashboard Finance → Platform fees panel surfaces these grouped by source. The card fee applies on the fiat capture path; the stablecoin/x402/glUSD fees apply on their crypto settlement paths in the asset's base units.
GET /x402/merchants/:merchantId/owed
Automated owed-balance computation. Returns, per network + asset, the merchant's settlement position with every amount as a decimal string of the asset's on-chain base units (fully precise for 18-decimal assets):
owed = collected − fees − refunded − alreadyPaid (clamped ≥ 0)
where collected sums verified x402 payments across the merchant's endpoints plus
verified crypto checkout transactions, fees sums the crypto fee ledger, refunded
sums refunded x402 payments, and alreadyPaid sums prior on-chain payouts.
POST /x402/merchants/:merchantId/payouts/owed
Compute what the merchant is owed for a single network + asset and settle
exactly that amount on-chain — no caller-specified amount. Rejects with 400
when nothing is owed and fails closed (503) when the settlement wallet is
unconfigured.
| Field | Type | Required | Description |
|---|---|---|---|
to | string | Yes | Destination address — EVM (0x…) or Solana (base58), matching network |
network | string | Yes | base, ethereum, bsc, or solana |
asset | string | Yes | USDC, USDT, or glUSD |
The response matches POST /payouts (a recorded x402_payouts row with the real
txHash), where amount is the computed owed base units.
Merchant Endpoint Registration
Register your API endpoints to be monetized via x402.
/x402/merchants/:merchantId/endpointsRegister a monetized endpoint/x402/merchants/:merchantId/endpointsList registered endpoints/x402/merchants/:merchantId/usageGet usage analytics and revenuePOST /x402/merchants/:merchantId/endpoints
| Field | Type | Required | Description |
|---|---|---|---|
urlPattern | string | Yes | URL pattern to monetize (supports wildcards) |
price | string | Yes | Price per request in the asset's on-chain base units, as a decimal integer string (min "1", up to 78 digits). A JSON integer is accepted for compatibility, but 18-decimal prices (ETH, BSC stablecoins) exceed JSON number precision: always send a string. |
currency | string | No | USDC, USDT, or glUSD (default: USDC) |
scheme | string | No | exact, metered, or subscription (default: exact) |
network | string | No | Preferred blockchain network (default: base) |
description | string | No | Human-readable description of the endpoint |
TypeScript SDK
Python SDK
Server-Side Integration
Here is how to protect your API endpoints with x402 on the server side.
Express.js Middleware
Pricing Models
| Model | Description | Use Case |
|---|---|---|
| Exact | Fixed price per request | Simple API calls, data lookups |
| Metered | Price based on usage (tokens, bytes, compute time) | AI inference, streaming, large queries |
| Subscription | Recurring access with usage limits | SaaS APIs, data feeds, premium tiers |
Metered Pricing Example
For metered endpoints, the final cost is determined after the request completes:
Supported Networks
| Network | Chain ID | Settlement Speed | Recommended For |
|---|---|---|---|
| Base | 8453 | ~2 seconds | Primary -- lowest fees, fastest settlement |
| Ethereum | 1 | ~12 seconds | High-value settlements |
| BSC | 56 | ~3 seconds | High-volume, low-fee EVM settlements |
| Solana | -- | ~0.4 seconds | High-throughput applications |
We recommend Base for most x402 integrations. It offers the lowest transaction fees and fastest settlement times while maintaining Ethereum-level security through optimistic rollups.
On-chain settlement assets
Payments are settled in SPL/ERC-20 stablecoins. The facilitator verifies that the submitted transaction credited the merchant's settlement address with at least the required amount of the expected token before issuing a receipt.
| Network | Payment proof (txHash) | USDC | USDT |
|---|---|---|---|
| Base | 0x transaction hash | 0x8335...02913 | 0xfde4...99bb2 |
| Ethereum | 0x transaction hash | 0xa0b8...6eb48 | 0xdac1...31ec7 |
| BSC | 0x transaction hash | 0x8ac7...d580d | 0x5533...97955 |
| Solana | base58 transaction signature | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
Every on-chain amount the facilitator stores or returns (price, payment
amount, totalRevenue, timeseries revenue, fees, owed balances) is a
decimal string of base units, exact up to 78 digits (uint256). Parse with
BigInt, never Number.
On BSC, both USDC and USDT use 18 decimals (unlike the 6-decimal USDC on
Base/Ethereum/Solana). Since an endpoint's price is denominated in the token's
base units, price BSC endpoints accordingly (e.g. 0.02 USDT = 20000000000000000).
On Solana, submit the base58 transaction signature as txHash. For inbound
verification the facilitator fetches the finalized transaction and confirms an
SPL-token credit to the settlement wallet's associated token account by diffing
pre/post token balances. Outbound settlement (refunds + payouts) is also
supported on Solana: it signs an SPL transferChecked from the platform's ed25519
Solana hot wallet (creating the recipient's associated token account if needed) and
returns the real base58 signature. glUSD on Solana uses its configured mint for both.
Next Steps
- Getting Started -- Set up your merchant account
- API Reference -- Full REST API documentation
- SDKs -- Language-specific SDK documentation
- Webhooks -- Listen for payment events