Pay the clearing price, once
A winning award can settle its exact atomic amount through x402 v2 EIP-3009. Payment buys one scheduled permit—not unlimited capacity, and never a bypass around admission.
Current state
Local mock
Implemented for development. Explicit opt-in exercises permits without moving money. It is not a production rail.
x402 exact
Implemented in source. The client and Worker use standard x402 v2 headers, strict EIP-3009 binding, and an approved facilitator profile.
Recovery
Implemented in source. Unknown facilitator outcomes lock the payment intent until authenticated dual-RPC reconciliation; confirmed intents can resume into capacity-backed admission without a second wallet authorization.
From bid to price
{
"awardId": "awd_...",
"clearingAmountAtomic": "4000",
"asset": "0x833589...a02913",
"network": "eip155:8453",
"settlementMode": "x402-exact",
"paymentDueByMs": "..."
}
The research/mock engine accepts sealed maxima and can clear up to K winners at one K+1 price, but bids are not funded at submission. Deployed real-value exact mode therefore disables competitive price formation: it requires one vetted client, one paid slot, reserve equal to maximum, and one outstanding paid obligation. The bid/award messages remain, but carry one fixed-price offer.
Exact target placement includes the configured payment timeout, bounded dual-RPC chain-observation timeout, settlement grace, and a fixed 2,000ms permit-delivery lead after auction close, rounded to a capacity interval. Deployed exact configuration requires at least 180,000ms for chain observation. The launch templates use 20 seconds, 240,000ms, 60,000ms polls, four attempts, and 10 seconds of grace: 272 seconds before rounding. The configured horizon must cover one interval + auction epoch + that lead. Targets never move beyond X429_MAX_FUTURE_WINDOWS; exhausted eligible targets return 503 auction_horizon_full. The client bids only when the latest possible paid slot fits its task deadline, and it rechecks the actual award window and signed payment deadline before authorizing USDC.
Two-step x402 settlement
- Call
POST /x429/v2/awards/{awardId}/settlewith the signed award, a fresh client proof, and an idempotency key—but without a payment signature. - The Worker returns
402and standardPAYMENT-REQUIRED, bound to the signed award, exact clearing amount, network, asset, payee, and validity window. - The policy-constrained client validates the requirement and signs one EIP-3009 authorization. It then awaits a durable write-ahead commit of its non-secret recovery record; a failed commit sends no payment request.
- Only after that commit, it calls the same endpoint once with
PAYMENT-SIGNATURE. - The Worker validates locally, verifies through the facilitator, claims the global authorization intent, and submits settlement. Facilitator success alone is not admission: in the synchronous deployed profile, two independently administered RPCs must agree on the Base
safetagged boundary block number and hash, the exact receipt/events, and the configured minimum depth within that agreed boundary before durable confirmation and one permit plusPAYMENT-RESPONSE.
The production configuration is designed for Base mainnet official USDC and the authenticated CDP facilitator profile. The public x402.org facilitator profile is restricted to Base Sepolia staging. This describes required configuration, not a claim that a funded production transaction has been completed.
safe, which typically takes about two minutes and is not irreversible. Base finalized, typically about 20 minutes, is reserved for delayed recovery, expired-unspent checks, refund proof, and transaction discovery rather than holding an interactive settlement request open.Bounded entitlement and refund evidence
Durable confirmation fixes one signed entitlementExpiresAtMs; recovery can move the permit to unused paid capacity but never extend that deadline. If redemption has not begun by expiry, the award becomes refund_due, cannot resume or redeem, and remains visible in the authenticated per-pool liability inventory.
The Worker does not hold a refund wallet key. After the payee sends the exact USDC amount back to the original payer, the operator records the exact transaction and log. Before accepting the refund, two independent RPC views re-prove the original settlement at a matching Base finalized boundary and agree on the finalized refund. The refund block must be strictly later than the bound settlement block, and both providers must agree its timestamp is at or after durable refundDueAtMs. One global refund-event claim prevents the same log from discharging two payment intents.
Terminal exact-payment records are retained instead of disappearing through routine cleanup. The authoritative close artifact comes from npm run payment:ledger:export, which traverses every current and retired pool's append-only financial-event journal through the permanent pool inventory and writes a private fixed-watermark NDJSON file plus SHA-256 manifest. payment:records:export is a current-state diagnostic projection only and cannot replace the source journal. Retired pool names must remain in the deployment inventory because Durable Objects are not globally enumerable.
Current pools also expose authenticated /x429/v2/admin/maintenance-health. One corrupt auction backs off independently while other due auctions continue, and global maintenance always attempts to schedule its next run.
npm run operations:check is the bundled fail-closed probe for current-pool alarm health, indeterminate payments, refund backlog, and entitlement-expiry warning. Production still needs an external scheduler, secret store, paging destination, and named owners; the command itself is not alert delivery.
X429_ISSUANCE_DISABLED=true stops new liabilities while preserving recovery. X429_SERVICE_DISABLED=true stops protected and normal client traffic; authenticated payment maintenance stays available. Its sole client-path exception validates and binds an exact submission already carrying PAYMENT-SIGNATURE, durably rejects it before facilitator I/O, and returns matching x429.payment.rejected. Malformed or response-lost attempts remain ambiguous.What is bound
- Signed award, ticket, subject, resource, method, request hash, slot, and payment deadline.
- Exact atomic amount, official asset contract, CAIP-2 network, and configured recipient.
- Payer address, EIP-3009 nonce, validity range, payload hash, requirements hash, and idempotency key.
- One global PaymentIntent Durable Object identity so the same authorization cannot settle two resources.
- One permit only after durable settlement confirmation; payment does not expand finite paid capacity.
Indeterminate means stop
Once PAYMENT-SIGNATURE is sent, a transport failure, any 5xx, missing or malformed PAYMENT-RESPONSE, malformed/truncated success body, receipt mismatch, or unrecognized response is different from a rejection: the facilitator may already have broadcast the authorization. The only automatic exception is one retry of explicit payment_confirmation_persistence_pending with the identical authorization, body, and idempotency key. Otherwise the reference client retains its already-durable recovery record and stops. Only the Worker's narrow matching HTTP 402 x429.payment.rejected shape is deterministic.
The Worker marks a known unknown outcome indeterminate, issues no permit, and leaves the linked free path locked. The client must not resend that authorization or create a replacement payment for the award.
The same rule applies when the facilitator reports success but the agreed Base safe boundary is unavailable, inconsistent, too shallow, or times out. Automatic proof is bounded to four attempts and 40 RPC requests total. A recovered confirmed intent is reverified and its canonical chain-evidence hash, security level, boundary block number, and boundary block hash must match the stored confirmation before admission can be created.
An operator calls POST /x429/v2/admin/payment-intents/{paymentIntentId}/reconcile with a bearer administrator token. For a confirmed resolution, both configured RPCs must agree on the exact authorization and transfer inside the selected agreed boundary. An expired-unspent resolution is allowed only after authorization expiry plus the safety margin, when both RPCs report the nonce unused at finalized. If the transaction hash was lost, the confirmed branch can instead request bounded Base-only discovery: both providers search a finalized range of at most 2,048 blocks using no more than eight discovery RPC requests for the exact AuthorizationUsed event. Discovery is not confirmation; the resulting transaction must then pass the normal dual-provider receipt/event/boundary verification. The runtime rejects identical hostnames; the operator must still choose independently administered providers and separately compare facilitator/accounting records.
npm run payment:reconcile -- \
--origin https://staging-api.example \
--payment-intent pi_<64-hex> \
--award-file ./award.txt \
--resolution confirmed \
--transaction 0x<64-hex> \
--permit-output .x429/private/reconciled-permit.json \
--token-stdin
Create .x429/private/ with mode 0700 first. --permit-output must name a new private file. The command reserves it before making the request, commits it with mode 0600, and never prints the redeemable permit to stdout. Keep the artifact in that ignored private tree as restricted operator evidence and never commit it. The reference resumeExactPayment() flow does not read this file; it obtains and verifies the current permit from the signed resume endpoint, so do not manually inject the saved permit into a request. When the transaction hash is genuinely unknown, replace --transaction 0x... with --discover-transaction while keeping --permit-output. Do not use discovery as a shortcut when a known transaction can be verified directly.
After confirmed reconciliation, the original client calls resumeExactPayment(). Discovery publishes paymentResume as POST /x429/v2/payment-intents/{paymentIntentId}/resume; the signed request contains the original award and idempotency key but no PAYMENT-SIGNATURE. If the original slot is too close or expired, the coordinator assigns one unused future paid slot outside auction target windows and rotates the permit nonce. If the recovery horizon is full, it retains confirmation and fails closed rather than invent capacity.
Operator gates
Generate a dedicated low-balance Base Sepolia payer without exposing its private key:
install -d -m 700 .x429/private
npm run payer:generate:staging -- \
--secret-output .x429/private/base-sepolia-payer.json \
--acknowledge TEST_ONLY_BASE_SEPOLIA_LOW_BALANCE_WALLET
The helper is staging-only. It writes one new mode-0600 gitignored file and prints only the public address. Fund only that address with faucet-issued Base Sepolia test ETH and official test USDC; never paste the private file or key into chat, argv, Wrangler, or the Worker. Mainnet payer provisioning is deliberately not claimed by this release.
- Use a dedicated, limited-balance staging payer and known payee before any production wallet.
- Run the exact Worker suite, staging preflight, funded Base Sepolia canary, duplicate-payment test, both reconciliation branches, and late-confirmation resume into a newly capacity-backed slot.
- Keep payer keys outside the Worker and constrain origin, network, asset, recipient, and maximum spend in the client signer.
- Monitor facilitator failures, indeterminate intents, RPC disagreement, clearing anomalies, and unpaid winners.
- Complete independent security and legal review before production funds.
- Keep competitive real-value bidding disabled. Re-enable it only after collateral or pay-before-allocation, sharded clearing, and independent security and economic review are implemented.