Integrate18
x402 payments
CompliR has no API keys; a request pays for itself. The first call answers 402 with what to sign, the client signs a USDC authorization, retries, and CompliR verifies and settles it through Circle's facilitator on Arc before returning the verdict. Nothing is charged when the handler fails; nothing settled is ever silently kept.
The 402 flow
client CompliR Circle facilitator (Arc)
│ POST /api/v1/screen │ │
│ ───────────────────────────────────►│ │
│ 402 + PAYMENT-REQUIRED │ │
│ ◄───────────────────────────────────│ │
│ sign EIP-3009 TransferWithAuthorization (USDC, 0.01) with the payer key │
│ POST again + PAYMENT-SIGNATURE │ │
│ ───────────────────────────────────►│ /verify ────────────────────────────► │
│ │ ◄──────────────────────── isValid │
│ │ run the handler (screen) │
│ │ /settle (payment-identifier = nonce) ►│
│ │ ◄──────────────── transaction, payer │
│ 200 + PAYMENT-RESPONSE + verdict │ │
│ ◄───────────────────────────────────│ │// 402 body and PAYMENT-REQUIRED (base64 of the same object)
{
"x402Version": 2,
"error": "PAYMENT-SIGNATURE header is required",
"resource": { "url": "https://trycomplir.xyz/api/v1/screen", "description": "CompliR screen: one address", "mimeType": "application/json" },
"accepts": [{
"scheme": "exact", "network": "eip155:5042", "amount": "10000", // 0.01 USDC in 6-dp atomic units
"asset": "0x3600000000000000000000000000000000000000", "payTo": "0x…", // X402_PAY_TO (the Circle revenue wallet)
"maxTimeoutSeconds": 60,
"extra": { "assetTransferMethod": "eip3009", "name": "USDC", "version": "2" } // EIP-712 domain of USDC on Arc
}]
}Protocol: x402 v2 (x402Version: 2), scheme exact on eip155:5042, transfer method eip3009. The CompliR SDK and MCP server implement the client side; the header and status reference is on HTTP API.
What the server guarantees
- Fail closed. Any verify or settle problem answers 402 or 502 and the handler's body is never leaked.
- Handler first, then settle (default): a failing or refusing handler is never charged.
settleFirstis used only where the side effect must not happen unpaid (the tip stake); anything that fails after that settlement is auto-refunded. - Idempotent per nonce for 5 minutes. A retry after a settled payment replays the cached response without a second settle; a retry after
settlement_pendingre-settles without re-running the handler; concurrent duplicates share one in-flight attempt. - Requirements are re-checked against the signed payload: scheme, network, asset, payTo, amount, authorization.to, authorization.value, validAfter and validBefore. Signing for less than the current price is rejected before anything runs.
- One payment per authorization on Circle too: the settle call carries the
payment-identifierextension derived from the EIP-3009 nonce (complir_<nonce>), so a client retry converges on one payment. - Pending settlements are polled up to 3 times (
X402_PENDING_POLLS) via the facilitator's status endpoint before the client is asked to retry with the same authorization.
Facilitator and config
- X402_DISABLED
- 1 today (every call free, X-CompliR-Payment: disabled). Set 0 to charge.
- X402_FACILITATOR_URL
- https://api.circle.com/v1/facilitator/x402 (Circle Facilitator Service, Arc native)
- X402_FACILITATOR_API_KEY
- Circle Console key → Authorization: Bearer; required for production settle
- X402_SELLER_PRIVATE_KEY
- alternative keyless trial: Facilitator-Seller-Proof signed by the X402_PAY_TO key
- X402_PAY_TO
- where USDC lands - the Circle revenue wallet once provisioned
- X402_NETWORK
- CAIP-2; defaults to eip155:$ARC_CHAIN_ID
- X402_ASSET_NAME / _VERSION
- EIP-712 domain of the token, default USDC / 2
- PRICE_SCREEN_USDC / PRICE_WATCH_USDC
- config defaults 0.01 / 0.05; the operator may move them inside its bounds
The same-origin free rule
Requests whose browser sends Sec-Fetch-Site: same-origin bypass x402 on /api/v1/screen, /api/v1/watch and /api/v1/tips. That is what keeps the hosted Explorer, Shadow and Tips pages free to use: they are thin views over the same handlers. An API client, a curl from another host or an agent never sends that header and always pays (unless X402_DISABLED=1). Screens made this way are recorded under the internal client id web-explorer and never count as traction.
Gateway-batched x402 (Circle Nanopayments) is not implemented: it would fit the buyer side of the tip stake, but the SDK is not installed and Arc settlement here goes through the standard facilitator.