x402 Pay-per-call
x402 (HTTP 402 Payment Required) turns Pry into a crypto pay-per-call
API — no account, no subscription. Clients pay USDC/SOL per call
directly from a wallet, and AI agents can pay automatically. In the x402
lane the payment is the credential, so no API key is needed; the
hosted/API lanes still use API keys.
Enable it with:
PRY_X402_ENABLED=true
# Receiving wallets are CAIP-2 keyed — one per network family:
PRY_X402_WALLET_BASE=0x... # EVM treasury (shared across EVM chains)
PRY_X402_WALLET_SOLANA=... # distinct base58 address
PRY_X402_WALLET_TRON=... # distinct T-prefix address
PRY_X402_FACILITATOR=https://x402.org/facilitator # or your own facilitator
How x402 works
- Client calls a paid endpoint without a payment → Pry responds
402 Payment Requiredwith aPAYMENT-REQUIREDheader (Base64-encodedPaymentRequiredJSON: wallet, amount, asset, facilitator). - Client pays — sends USDC/USDT (or native asset) to the receiving wallet on the configured chain.
- Client submits the tx to
POST /v1/x402/paywith thetx_hash. - Pry verifies the transaction on-chain (via the facilitator router, or
EIP-7702 self-verify), then returns an access token (
payment_id). - Client replays the token with the
X-Payment-Idheader until it expires (PRY_X402_PAYMENT_TTL, default 3600s).
The x402 v1 spec is implemented per
coinbase/x402 on GitHub (upstream
spec reference, not our repo). The middleware
reads the PAYMENT-SIGNATURE header (Base64-encoded JSON of the signed
payment) for facilitator flow, and issues the PAYMENT-REQUIRED header on
402s.
Payment headers
| Header | Direction | Meaning |
|---|---|---|
PAYMENT-REQUIRED | 402 response | Base64-encoded PaymentRequired body (wallet, amount, asset, facilitator) |
PAYMENT-SIGNATURE | request | Base64-encoded JSON of the signed payment (facilitator flow) |
X-Payment-Id | request | Access token from /v1/x402/pay — replay until TTL expires |
X-Batch-Payment-Id | request | Access token for a batch payment covering multiple operations |
GET /v1/x402/pricing
Get the authoritative price list for all paid operations.
curl https://api.pryscraper.com/v1/x402/pricing
Response (200): per-operation prices in USD:
{
"scrape": {"price_usd": 0.001, "description": "Single URL scrape"},
"crawl": {"price_usd": 0.01, "description": "Crawl up to 10 pages"},
"extract": {"price_usd": 0.005, "description": "Structured extraction"},
"monitor": {"price_usd": 0.02, "description": "Create scheduled monitor"},
"llm_call": {"price_usd": 0.01, "description": "LLM extraction call"},
"template_execute": {"price_usd": 0.002, "description": "Execute scraper template"},
"bulk_crawl": {"price_usd": 0.10, "description": "Crawl up to 1000 pages"},
"browser_automation":{"price_usd": 0.05, "description": "Browser automation"},
"pdf_extract": {"price_usd": 0.01, "description": "PDF table extraction"},
"ocr_extract": {"price_usd": 0.005, "description": "Image OCR"},
"schema_extract": {"price_usd": 0.002, "description": "Schema.org/JSON-LD extraction"}
}
The server is authoritative — client-supplied underpayment is rejected.
validate_client_amount refuses any amount below the server price for the
operation. Unknown operations are not gated.
Full pricing table (as shipped)
| Operation | Price (USD) | Description |
|---|---|---|
scrape | $0.001 | Single URL scrape |
crawl | $0.01 | Crawl up to 10 pages |
bulk_crawl | $0.10 | Crawl up to 1000 pages |
extract | $0.005 | Structured extraction |
schema_extract | $0.002 | Schema.org / JSON-LD extraction |
llm_call | $0.01 | LLM extraction call |
monitor | $0.02 | Create scheduled monitor |
browser_automation | $0.05 | Browser automation |
pdf_extract | $0.01 | PDF table extraction |
ocr_extract | $0.005 | Image OCR |
template_execute | $0.002 | Execute scraper template |
template_batch_execute | $0.01 | Execute up to 20 template items |
graphql_query | $0.003 | GraphQL query execution |
POST /v1/x402/payment
Create a payment request for a paid operation. Returns payment details (wallet, amount, asset) for the client to pay.
Request body:
| Field | Type | Description |
|---|---|---|
operation | string | Required. Operation being paid for (e.g. scrape) |
metadata | object | Optional metadata |
Response (200): { "wallet": "...", "amount": 0.001, "asset": "USDC", "facilitator": "...", ... }
POST /v1/x402/require-payment
Generate a 402 Payment Required response for a paid endpoint.
Request body: same as /v1/x402/payment (operation, optional metadata).
Response (402): spec-compliant 402 with the PAYMENT-REQUIRED header.
POST /v1/x402/pay
Process an x402 payment and get an access token.
Flow: user gets 402 from a paid endpoint → sends USDC to the wallet in the
402 response → calls this endpoint with the tx_hash → Pry verifies the
transaction through the facilitator router → returns an access token
(payment_id) for the X-Payment-Id header.
Request body:
| Field | Type | Default | Description |
|---|---|---|---|
operation | string | — | Required. Operation paid for |
tx_hash | string | — | Required. On-chain transaction hash |
payer_wallet | string | — | Required. Payer wallet address |
network | string | — | Chain (e.g. base, solana, ethereum) |
asset | string | — | Asset (USDC/USDT/native) |
amount_usd | number | 0.0 | Paid amount in USD |
Response (200): { "payment_id": "...", "expires_at": "...", ... }
POST /v1/x402/verify
Verify a payment has settled on-chain via the facilitator router.
Request body:
| Field | Type | Description |
|---|---|---|
payment_id | string | Required. Payment ID from /v1/x402/pay |
tx_hash | string | Required. Transaction hash |
network / asset / amount_usd | — | Optional verification context |
Batch payments
For multi-operation calls (e.g. a crawl that triggers many extractions), use batch payments to pay once:
| Endpoint | Purpose |
|---|---|
POST /v1/x402/batch-payment | Create a single x402 payment covering multiple operations → returns a PaymentRequired body with the combined amount |
POST /v1/x402/batch-verify | Verify the on-chain payment for a batch and mark it paid → returns X-Batch-Payment-Id |
Supported networks & assets
Payments are accepted across EVM ERC-20 (USDC on Base, Ethereum,
Arbitrum, Optimism, Polygon) and Solana SPL (SOL/USDC/USDT). The
canonical acceptance table lives in x402/scheme.py
(SUPPORTED_NETWORKS / SUPPORTED_ASSETS, keyed by CAIP-2 network id).
Verification status matters. EVM settlement verification is real and turnkey (EIP-7702 self-verify + external facilitators). Solana is supported — the scaffold validates the payment header, price, and asset, and settlement verification runs through an SPL / facilitator verifier. TRON, BNB and Avalanche remain scaffolding and are not part of the default acceptance table.
| Network | Family | Assets | Verification | Status |
|---|---|---|---|---|
| Base | EVM | USDC, USDT, ETH, WETH | eip3009 / permit2 / native | ✅ Turnkey |
| Ethereum | EVM | USDC, USDT, ETH, WETH | eip3009 / permit2 / native | ✅ Turnkey |
| Arbitrum | EVM | USDC, USDT, ARB, ETH, WETH | eip3009 / permit2 / native | ✅ Turnkey |
| Optimism | EVM | USDC, USDT, ETH, WETH | eip3009 / permit2 / native | ✅ Turnkey |
| Polygon | EVM | USDC, USDT, POL, WETH | eip3009 / permit2 / native | ✅ Turnkey |
| Solana | SPL | SOL, USDC, USDT | spl / native | ✅ Supported |
| TRON | TRC-20 | USDT, TRX | trc20 / native | 🚧 Scaffold (not default) |
Verification methods:
| Method | Meaning |
|---|---|
eip3009 | ERC-20 transferWithAuthorization (USDC) |
permit2 | ERC-20 Permit2 (USDT / ARB / WETH / …) |
native | Plain value transfer of the chain's native asset |
spl | Solana SPL token transfer |
trc20 | TRON TRC-20 transfer |
Per-network receiving wallets are CAIP-2 keyed — a Solana address is not
the same as an EVM wallet, so operators MUST set PRY_X402_WALLET_SOLANA and
PRY_X402_WALLET_TRON before accepting real payments on those chains:
| Network | Env var |
|---|---|
| Base | PRY_X402_WALLET_BASE |
| Ethereum | PRY_X402_WALLET_ETHEREUM |
| Arbitrum | PRY_X402_WALLET_ARBITRUM |
| Optimism | PRY_X402_WALLET_OPTIMISM |
| Polygon | PRY_X402_WALLET_POLYGON |
| Solana | PRY_X402_WALLET_SOLANA |
| TRON | PRY_X402_WALLET_TRON |
Canonical ERC-20 addresses per chain are validated during EIP-7702
self-verify. Base Sepolia is available for testing (base-sepolia, USDC).
Default network: base (PRY_X402_NETWORK); default asset: USDC
(PRY_X402_ASSET).
Verification: facilitators vs self-verify vs self-facilitator
Pry has three ways to confirm a payment settled on-chain:
-
External facilitator (default) — the classic x402 v1 flow: the client signs the payment and Pry verifies it through a facilitator URL (
PRY_X402_FACILITATOR, defaulthttps://x402.org/facilitator). Supported facilitators:coinbase,payai,cloudflare,eip-7702, with a smart router that auto-falls back to the next available one. -
EIP-7702 self-verify — no facilitator for the verification step: Pry reads the canonical token addresses and public RPC endpoints directly (overridable via
PRY_X402_*_RPC) to confirm the payment transaction on-chain. EIP-7702 allows EOAs to delegate account code, which the x402 flow leverages for cheap, facilitator-independent settlement verification. Turnkey on EVM. -
Self-hosted facilitator (no Coinbase) — opt-in with
PRY_X402_SELF_FACILITATE=1: Pry runs its own local facilitator (x402/self_facilitator.py) that performs EIP-3009 verification and broadcasts the settlement on your own infra — no external facilitator and no Coinbase CDP dependency.
# Self-facilitation: verify + settle entirely on Pry infra
PRY_X402_SELF_FACILITATE=1
PRY_X402_FACILITATOR_KEY=... # EVM private key used to pay gas for the settlement broadcast
PRY_X402_FACILITATOR_RPC=... # JSON-RPC endpoint for the settlement chain
If the key and RPC are not both set, verification still works but the settlement broadcast is unavailable (a warning is logged at startup).
EIP-7702 self-verify RPCs
| Network | Default RPC | Override env |
|---|---|---|
| Base | https://mainnet.base.org | PRY_X402_BASE_RPC |
| Ethereum | https://eth.llamarpc.com | PRY_X402_ETH_RPC |
| Polygon | https://polygon.drpc.org | PRY_X402_POLYGON_RPC |
| Arbitrum | https://arb1.arbitrum.io/rpc | PRY_X402_ARBITRUM_RPC |
| Optimism | https://mainnet.optimism.io | PRY_X402_OPTIMISM_RPC |
| BNB | https://bsc-dataseed.binance.org | PRY_X402_BNB_RPC |
| Avalanche | https://api.avax.network/ext/bc/C/rpc | PRY_X402_AVALANCHE_RPC |
| Base Sepolia | https://sepolia.base.org | PRY_X402_BASE_SEPOLIA_RPC |
bnb and avalanche have RPC + token-address scaffolding in the EIP-7702
table, but they are not yet in the canonical SUPPORTED_ASSETS acceptance
table — don't rely on them for production payments until they're promoted
in x402/scheme.py.
Turning the API into revenue
x402 is one of three monetization lanes (see Pricing & Monetization):
- Self-hosted free — run Pry yourself, MIT core. No per-call fees.
- x402 pay-per-call — enable
PRY_X402_ENABLED=true, point thePRY_X402_WALLET_*vars at your per-network treasuries, and every scrape/crawl/extract earns micropayments from AI agents and bots. Prices above are defaults; the pricing table lives inx402.pyand is served by/v1/x402/pricing. - Hosted subscription — the managed service at pry.dev with Pro/Team plans.
AI agents integrate automatically through the
MCP server — pry_x402_pricing is one of the built-in
MCP tools.
Bulk scrape packs (credit packs)
For high-volume and scheduled work, skip the per-call x402 round-trip by buying a scrape pack — a prepaid block of credits at a discounted effective per-call rate. A single crypto top-up covers thousands of calls; each request draws down the pack instead of paying per request. Credits roll over month to month, and there's no KYC.
| Pack | Credits | Effective rate | Best for |
|---|---|---|---|
| Starter | 10,000 | ~$0.004/call | trialing at scale |
| Pro | 100,000 | ~$0.003/call | cron monitors, batch jobs |
| Scale | 500,000 | ~$0.0025/call | agents + heavy pipelines |
[REVIEW] Confirm pack credit/pricing math against the billing module.
Crypto subscriptions (monthly tiers)
Beyond per-call payments, Pry ships a crypto subscription billing module
(billing/) for the monthly Pro/Team/Enterprise tiers. It reuses the x402
self-facilitator machinery to collect monthly fees in crypto — with a BTCPay
Server fallback when PRY_BTCPAY_URL + PRY_BTCPAY_API_KEY + PRY_BTCPAY_STORE
are configured — and enforces monthly quotas + per-minute rate limits via
billing.enforcer. The module is provider-agnostic and currently integrated
into self-hosted deployments (not exposed as a hosted HTTP checkout yet);
see billing/subscription.py for the activation flow.
PRY_X402_OFFLINE=true makes every verify succeed without a facilitator —
it requires DEBUG=true (or PRY_DEBUG=true) and must never be enabled in
production.
Next steps
- Pricing & Monetization — the three lanes
- MCP Integration — AI agents pay automatically