x402 integration
x402 is an HTTP-native payment protocol for paid APIs and paid content.
Your service returns 402 Payment Required with payment requirements, the client signs payment data, and retries with an X-Payment header.
On Radius, this pattern suits micropayments well: transaction costs are low and predictable.
What x402 enables
Per-request API billing — meter each call and settle instantly, no monthly invoices or credit card rails
Pay-per-visit content — gate articles, data feeds, or downloads behind a single micropayment instead of a subscription
Streaming payments — combine x402 with a payment loop to charge continuously for compute, bandwidth, or inference by the second
Request lifecycle
Understanding this flow before writing code makes the endpoint pattern and facilitator role easier to follow.
- A client requests a protected resource.
- Your service responds with
402 Payment Requiredand an x402 requirement object. - The client signs payment data and retries with an
X-Paymentheader. - The facilitator verifies and settles the payment on Radius.
- Your service returns
200 OKand serves the protected response.
Minimal endpoint pattern
This structure works in a gateway, API server, or edge worker. The key branches are: return 402 with requirements when there's no X-Payment header, verify and settle when there is one, and return 200 on success.
function handleRequest(request):
if not isProtectedPath(request.path):
return serveResource(request)
xPayment = request.headers["X-Payment"]
if xPayment is missing:
requirement = {
scheme: "exact",
network: "radius",
maxAmountRequired: toBaseUnits("0.10"),
resource: request.url,
description: "Access to protected resource",
payTo: "{{MERCHANT_ADDRESS}}",
asset: "{{TOKEN_ADDRESS}}"
}
return response(
status=402,
headers={ "X-Accept-Payment": stringify(requirement) },
body={
error: "Payment required",
x402Version: 1,
accepts: [requirement]
}
)
result = facilitator.verifyAndSettle(xPayment)
if result.ok is false:
return response(status=402, body={ error: result.error })
return response(
status=200,
body=serveResource(request),
headers={
"X-Payment-Verified": "true",
"X-Payment-Payer": result.payer,
"X-Payment-Transaction": result.txHash
}
)Sample 402 response
This is the core payload your service returns when payment is required.
{
"error": "Payment required",
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"network": "radius",
"maxAmountRequired": "100000000000000000",
"resource": "https://api.example.com/premium/report",
"description": "Access to /premium/report",
"mimeType": "application/json",
"payTo": "0x{{MERCHANT_ADDRESS}}",
"asset": "0x{{TOKEN_ADDRESS}}",
"maxTimeoutSeconds": 300
}
]
}Choose your facilitator
Use a hosted facilitator when
- You need the fastest path to production
- You want lower operational overhead
- You want to validate product demand before running settlement infrastructure
Build your own facilitator when
- You need custom policy, risk, or compliance checks
- You need custom settlement routing or treasury controls
- You want full ownership of keys, infrastructure, and observability
Stablecoin.xyz hosted facilitator
If you're on the hosted path, Stablecoin.xyz offers a facilitator configured for x402 on Radius:
Token compatibility for x402
The token you use for settlement determines which settlement strategies are available to you. This table compares USDC and SBC against the EIP standards x402 facilitators rely on.
EIP support at a glance
| Standard | USDC (FiatTokenV2_2) | SBC (Radius native) | x402 impact |
|---|---|---|---|
| EIP-20 | ✅ | ✅ | No gap for basic token transfers |
| EIP-712 | ✅ | ✅ | Typed data signing supported |
EIP-2612 (permit) | ✅ | ✅ | Signature-based approvals supported |
EIP-3009 (transferWithAuthorization) | ✅ | ❌ | Standard one-transaction x402 settlement path is unavailable |
| EIP-1271 (smart contract wallet signature validation) | ✅ | ❌ | Smart account compatibility is reduced for signature-based payment flows |
| EIP-1967 (proxy slots) | ✅ | ✅ | Not a functional blocker for x402 flow design |
Why EIP-3009 matters for x402
EIP-3009 enables direct signed transfer execution via transferWithAuthorization. In practice, that means:
- one on-chain settlement call
- no persistent allowance footprint
- random nonce model that supports concurrent authorizations
- explicit validity window controls (
validAfterandvalidBefore)
Without EIP-3009, a facilitator falls back to an EIP-2612 pattern:
- Submit
permit()to set allowance. - Submit
transferFrom()to move funds.
That two-transaction path increases gas usage, adds latency, and creates a non-atomic gap where allowance is set before transfer finalizes.
Why EIP-1271 matters
EIP-1271 standardizes signature validation for smart contract wallets. Without it in the token flow, compatibility narrows for smart accounts and multisig-style wallets in signature-based payment patterns.
For teams targeting account abstraction-heavy user bases, this affects wallet support expectations and integration testing scope.
x402 implications on Radius
Given the SBC capability profile, the practical settlement path is:
- Use a custom facilitator flow based on EIP-2612
permit+transferFrom. - Enforce strict nonce, amount, and expiry checks.
- Implement robust idempotency and replay protection.
- Monitor settlement outcomes to detect partial or failed two-step execution.
The Radius reference implementation includes both strategy paths and makes permit-transferFrom the baseline fallback when EIP-3009 is not available.
Validation checklist
Before settlement, validate all of the following:
schemematches your expected scheme (for example,exact)networkmatches Radiusassetis the token contract you acceptpayTomatches your payment address- Signed amount is greater than or equal to required amount
- Signature is valid and signer identity matches payload
- Nonce and validity window checks pass
- Payer balance is sufficient
- Settlement wallet has enough native gas balance
After settlement:
- Wait for transaction receipt.
- Return deterministic success metadata.
- Record idempotency key and tx hash for replay protection.
Facilitator settlement pseudocode
function verifyAndSettlePayment(xPayment, config):
payment = decodeXPayment(xPayment)
require payment.scheme == "exact"
require payment.network == config.networkName
require payment.asset == config.asset
require payment.payTo == config.paymentAddress
if config.strategy == "permit-transferFrom":
require payment.payload.kind == "permit-eip2612"
require payment.payload.spender == config.settlementSpender
require now < payment.payload.deadline
require payment.payload.value >= config.requiredAmount
signer = recoverPermitSigner(payment.payload, config.domain)
require signer == payment.payload.owner
submitPermitTransaction(...)
assertAllowanceAtLeast(config.requiredAmount)
txHash = submitTransferFrom(...)
return { ok: true, payer: payment.payload.owner, txHash: txHash }
if config.strategy == "transferWithAuthorization":
require payment.payload.kind == "eip3009-transfer-with-authorization"
require payment.payload.to == config.paymentAddress
require payment.payload.value >= config.requiredAmount
require payment.payload.validAfter <= now <= payment.payload.validBefore
txHash = submitTransferWithAuthorization(...)
return { ok: true, payer: payment.payload.from, txHash: txHash }
return { ok: false, error: "Unsupported settlement strategy" }Radius implementation notes
- Configure clients and settlement services for Radius network settings.
- Use Radius-compatible gas handling in your transaction path.
- Keep settlement wallets funded for native gas.
- Use short validity windows to reduce replay risk.
- Add structured logs for verification failures and settlement outcomes.