x402 is a machine-native payment protocol built on HTTP 402 Payment Required. An agent makes a normal HTTP request to a paywalled endpoint, the server responds with payment instructions, the agent signs an on-chain authorization, and retries the request — the SDK handles the round-trip automatically. MoonPay Commerce exposes two x402-paywalled endpoints: checkout (one-time payments against a paylink) and deposit (recurring or balance-based payments).Documentation Index
Fetch the complete documentation index at: https://docs.hel.io/llms.txt
Use this file to discover all available pages before exploring further.
All payments use real mainnet USDC. There is no testnet x402 endpoint. Confirm the amount, chain, and recipient with the user before every payment.
What is x402?
x402 is a “pay-to-play” standard for HTTP APIs. Instead of an account, API key, or subscription, the client pays per request directly in stablecoins. Key properties:- No subscription — pay only for what you use
- Permissionless — no account creation, KYC, or merchant approval
- Crypto-native — USDC settled on Base, Ethereum, Polygon, Arbitrum, BSC, or Solana
- Agent-friendly — every step is a single HTTP exchange; no UI, redirects, or sessions
How the Flow Works
@x402/fetch, x402 Python, etc.) — application code only sees a single POST and the final response.
API Endpoints
Base URL:https://api.hel.io
| Method | Path | Description |
|---|---|---|
POST | /v1/x402/checkout/{paylinkId} | One-time checkout payment against a paylink |
POST | /v1/x402/deposit/{depositId} | Recurring / balance-based deposit payment |
GET | /v1/paylink/{id}/public | Fetch product metadata (requires Origin header) |
POST endpoints return HTTP 402 until a valid PAYMENT-SIGNATURE is presented.
Supported Chains
| Chain | CAIP-2 | Notes |
|---|---|---|
| Base | eip155:8453 | Lowest gas — recommended default |
| Ethereum | eip155:1 | Higher gas |
| Polygon | eip155:137 | Low gas |
| Arbitrum | eip155:42161 | Low gas |
| BSC | eip155:56 | Low gas |
| Solana | solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp | Fastest settlement (~5–10s) |
accepts[], prefer Base unless the agent’s wallet is funded elsewhere. If gas spikes beyond the per-chain threshold, that chain is excluded from accepts[]; if all chains are excluded, the server returns 400 instead of 402 — retry later.
Amount Conversion
USDC has 6 decimals:minimalUnits = USD × 1_000_000.
| USD | Minimal units |
|---|---|
| $1.00 | 1000000 |
| $3.00 | 3000000 |
| $10.00 | 10000000 |
| $100.00 | 100000000 |
amount returned by the 402 response is the total cost including fees and gas — no further calculation is required client-side.
Pay with the MoonPay CLI
The fastest way to make an x402 payment is the MoonPay CLI (mp). It manages the wallet, signs the on-chain authorization, and handles the 402 round-trip.
Prerequisites
- MoonPay CLI installed and authenticated —
mp wallet listshould show your wallet - Wallet funded with mainnet USDC on the target chain
- A MoonPay Commerce paylink URL (e.g. from moonpay.hel.io)
Step 1 — Discover the product
Before paying, fetch the public paylink metadata so you can confirm the product, price, and supported chains:Step 2 — Get the payer address
Step 3 — Confirm with the user
Restate the amount, chain, and recipient before spending real funds. For an agent integration, this is a hard requirement — never auto-execute.“About to send $10.00 USDC on Base mainnet for DEX Screener Token Boost (paylinkabc123), signed from wallet<name>. Proceed?”
Step 4 — Pay
Fixed-price paylink:&amount=<minimalUnits>:
Step 5 — Confirm settlement
The CLI prints the settlement transaction hash on success. Surface it to the user:
“Paid $10.00 USDC on Base mainnet (settle tx 0x…). Wallet balance: $X → $X-10.”
Settlement is asynchronous — the HTTP 200 returns as soon as the signature is verified, but the on-chain sweep from the per-payer deposit wallet to the merchant takes ~30–120s on mainnet.
Pay with an x402 SDK
Any x402-compatible client works against MoonPay Commerce — just remember to append?payerAddress=<wallet> to the URL.
Prerequisites
- Node.js, Python, or Go
- Wallet private key (loaded from environment variable — never commit)
- USDC balance on the target chain
Install
- Node.js / TypeScript
- Python
- Go
Make a Payment
- Node.js (fetch)
- Python (httpx)
- Go
Multi-Chain Support
Register multiple schemes to pay from any supported network:accepts[]. If the wallet is funded on Base only, ensure your client preference selects Base when multiple chains are offered.
Manual Payment Flow (No SDK)
If an SDK isn’t an option, you can drive the protocol with raw HTTP calls.Step 1 — Initial request
Step 2 — Decode the 402 response
The server returnsHTTP 402 with a PAYMENT-REQUIRED header containing Base64-encoded JSON:
amountis the total cost in minimal units — fees and gas are already included.payTois a per-payer deposit wallet, not the merchant’s address. Funds sweep to the merchant after settlement.- Each entry in
accepts[]is one supported chain — pick the one your wallet is funded on.
Step 3 — Sign the on-chain authorization
- EVM chains — sign an EIP-3009
transferWithAuthorizationforamountUSDC topayTo. - Solana — build an SPL token transfer of
amountUSDC topayTo.
Step 4 — Retry with the signed proof
Step 5 — Read the settlement receipt
The200 OK response includes a PAYMENT-RESPONSE header with the on-chain settlement transaction hash:
Error Handling
| HTTP | Code / Condition | What to do |
|---|---|---|
| 402 | No payment signature | Decode PAYMENT-REQUIRED, sign, retry with PAYMENT-SIGNATURE |
| 400 | Missing payerAddress | Append ?payerAddress=<wallet> to the URL |
| 400 | PAYLINK_INACTIVE | Paylink disabled — do not retry |
| 400 | PAYLINK_DELETED | Paylink deleted — do not retry |
| 400 | X402_UNSUPPORTED_FEATURES | Paylink requires customer detail fields; not payable via x402 |
| 400 | FEE_MARGIN_INSUFFICIENT | Gas exceeds fee margin on all chains; retry later |
| 400 | FEE_RATE_EXCEEDS_PRICE | Fee rate exceeds payment price; surface to user |
| 400 | Empty accepts[] | All chains circuit-broken on gas; retry later |
| 400 | Invalid payer address | Validate format: 0x… for EVM, base58 for Solana |
| 400 | Invalid amount param | Must be a positive integer string in minimal units |
| 403 | PAYLINK_SANCTIONED | Access restricted; do not retry |
| 403 | Payer mismatch | Signed payer doesn’t match provisioned identity; verify wallet |
| 404 | Paylink not found | Verify the paylink ID is correct for production |
| 409 | Settlement in progress | A submission is already settling; do not re-submit |
| 429 | Rate limited | Back off — limit is 10 requests / 60s per IP |
Rate Limits
x402 endpoints are rate-limited per IP at 10 requests / 60 seconds. Agents that batch payments should serialize requests and back off on429.
Troubleshooting
x-payer-address header or ?payerAddress= query param required (400)
The payerAddress query parameter is missing. This is required by MoonPay Commerce and is non-standard for x402 — most SDKs do not send it. Always include ?payerAddress=<wallet> in the URL.
Payment verification failed / on-chain revert
The payer wallet has no USDC on the network the server allocated the deposit wallet for. Check mp token balance list --wallet <name> --chain <chain> — accepts[].network in the 402 response tells you which chain to fund.
All chains return 400 instead of 402
Gas spiked across all supported chains and the circuit breaker excluded them all from accepts[]. Wait for gas to settle (typically minutes) and retry.
409 Conflict — settlement in progress
A previous submission for this transaction is still being processed. Do not re-submit; wait 30–60s for settlement to resolve.
Pre-Payment Checklist
Before executing any payment, verify:- Wallet has sufficient USDC balance on the target chain
- Paylink ID is valid (confirmed via
GET /v1/paylink/{id}/public) ?payerAddress=<wallet>is included in the URL- Amount is correct — in minimal units (6 decimals), matches the product price
- User has explicitly confirmed: product name, amount, chain, and wallet
Resources
x402 Protocol
Official protocol specification and ecosystem
x402 Quickstart for Buyers
Coinbase’s getting-started guide for x402 clients
MoonPay CLI
mp — sign and submit x402 payments from the command linex402 GitHub
Reference clients in TypeScript, Python, and Go
Agent Payments Overview
Other agent-payable protocols and the merchant integration model
Webhooks
React to settled agent payments via paylink and deposit webhooks
