x402 reference
Limits
Section titled “Limits”| Limit | Value |
|---|---|
| Smallest payment | 0.005 of any token |
maxTimeoutSeconds | 1 to 3600 |
/verify | 600 requests per minute per account |
/settle | 300 requests per minute per account |
Requests over the rate limits get HTTP 429.
Packages
Section titled “Packages”The official packages send your API key and pick the facilitator URL for you.
Source code: cryptonly-net/x402 on GitHub.
Other x402 clients
Section titled “Other x402 clients”Any x402 facilitator client works. Point it at the facilitator URL and send your API key in the x-tenant-api-key header.
https://api-merchant.cryptonly.net/x402In the sandbox: https://sandbox-api-merchant.cryptonly.net/x402.
API key scopes
Section titled “API key scopes”An x402 key can only call x402 endpoints. It can’t create invoices or withdrawals, so it’s safe to keep on the server that sells your API.
| Scope | Allows |
|---|---|
x402.verify | POST /x402/verify, GET /x402/supported and GET /x402/config |
x402.settle | POST /x402/settle |
x402.list | GET /x402/settlements and GET /x402/settlements/{id} |
Buyer clients
Section titled “Buyer clients”The quickstart pays with TypeScript. The same call in Python and Go:
pip install "x402[httpx,evm]"import asyncioimport os
from eth_account import Accountfrom x402 import x402Clientfrom x402.http.clients import wrapHttpxWithPaymentfrom x402.mechanisms.evm.exact import register_exact_evm_clientfrom x402.mechanisms.evm.signers import EthAccountSigner
client = x402Client()register_exact_evm_client(client, EthAccountSigner(Account.from_key(os.environ["BUYER_PRIVATE_KEY"])))
async def main(): async with wrapHttpxWithPayment(client) as http: response = await http.get("http://localhost:4021/v1/weather/paris") print(response.status_code, response.json())
asyncio.run(main())go get github.com/x402-foundation/x402/gopackage main
import ( "fmt" "io" "net/http" "os"
x402 "github.com/x402-foundation/x402/go" x402http "github.com/x402-foundation/x402/go/http" evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" evmsigners "github.com/x402-foundation/x402/go/signers/evm")
func main() { signer, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("BUYER_PRIVATE_KEY")) if err != nil { panic(err) } client := x402.Newx402Client().Register("eip155:*", evm.NewExactEvmScheme(signer, nil)) pay := x402http.WrapHTTPClientWithPayment(http.DefaultClient, x402http.Newx402HTTPClient(client))
resp, err := pay.Get("http://localhost:4021/v1/weather/paris") if err != nil { panic(err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode, string(body))}Settle responses
Section titled “Settle responses”/settle sends the payment to the network and waits a few seconds for it to land in a block.
| Result | Response |
|---|---|
| Landed | success: true and the transaction hash. The buyer gets the response. |
| Not landed yet | success: false, errorReason: settlement_pending and the transaction hash. See below. |
| Refused | success: false and a reason code. Nothing is sent and no fee is charged. |
A successful response includes the expected fee in extra.feeAtomic, in the smallest unit of the token at extra.feeAsset. It’s 0 within the free tier. The fee actually charged is on the payment and in its webhook.
Retries are safe. Sending the same signed payment again returns the original transaction and sends nothing new.
After the response, the payment becomes confirmed, credited or failed. See Statuses.
Pending payments
Section titled “Pending payments”settlement_pending means the payment was sent but hadn’t landed when /settle answered. It usually lands a moment later. Stock x402 middleware still treats it as a failure and doesn’t return your response to the buyer. Its final status shows up on the Payments tab and in webhooks.
Reason codes
Section titled “Reason codes”/verify and /settle return failures as HTTP 200 with a reason, as the x402 specification requires. On top of the standard x402 reasons, Cryptonly uses these:
| Reason | What happened | What to do |
|---|---|---|
settlement_disabled | Your account is waiting for business verification, is suspended, or settlement is paused. | Finish business verification. Otherwise contact support. |
pay_to_rejected | payTo isn’t one of your wallets or your settlement address. | Use an address from Settings → Payouts. |
fee_balance_insufficient | Your x402 credits don’t cover the fee. | Top up credits or turn on auto top-up. |
compliance_rejected | The buyer or payTo failed sanctions screening, or screening was unavailable. | Contact support if you think this is a mistake. |
authorization_already_used | This signed payment was already settled. | Nothing. The buyer needs to sign a new payment. |
permit2_allowance_required | The buyer paid through Permit2 without approving it for the token. | The buyer approves Permit2 for the token. |
settlement_pending | Sent, but not in a block yet. | See Pending payments. |
invalid_exact_svm_recipient_token_account_missing | Solana: your wallet has no token account for this token. | Send the token to your wallet once. See Solana wallets. |
invalid_exact_svm_recipient_token_account_frozen | Solana: the token issuer froze your token account. | Use another wallet. |
invalid_exact_svm_recipient_token_account_invalid | Solana: your token account’s address holds something else. | Use another wallet. |
gas_ceiling_exceeded, gas_budget_exhausted, tenant_gas_budget_exhausted, fee_payer_reserve_low, fee_payer_busy | Cryptonly hit a limit on the network fees it pays, or is busy. | Try again later. Daily limits reset at 00:00 UTC. |
Something not covered here? Write to support@cryptonly.net.