What is Conduit
Conduit is an open x402 facilitator that implements the erc7710 settlement method on MetaMask Smart Accounts — and relays through the 1Shot Permissionless Relayer, so agents pay gas in stablecoins.
Point any x402-protected resource at a Conduit facilitator and your callers get: settlement via on-chain delegation redemption, a family of on-chain caveats that bind every action — X402ReceiptEnforcer for one exact request, X402SubscriptionEnforcer for fixed recurring charges, and SwapBounds/SwapAllowlist for bounded agent trades — gas paid in USDC with no relayer to run, and clean settlement webhooks. Conduit is the rail; your agent is the caller.
Quickstart
The x402 exchange is three steps. Your resource returns 402 with Conduit in extra; the caller pays via the X-PAYMENT header; Conduit verifies + settles.
# 1. Caller hits your resource → 402 Payment Required
GET /paid-data → 402 { accepts: [{ ...,
extra: { assetTransferMethod: "erc7710",
facilitator, delegationManager, receiptEnforcer,
redeemer, feeCollector, relayBackend } } ] }
# 2. Caller builds an intent-bound redelegation and re-requests
GET /paid-data
X-PAYMENT: base64(x402 payment payload)
# 3. Your server forwards to the facilitator → settles on-chain
POST {facilitator}/verify → { isValid }
POST {facilitator}/settle → { jobId, status, transaction }The seller never holds funds or keys — it just relays the payment payload to the facilitator. Conduit (and 1Shot) do the rest.
Facilitator API
The facilitator is a small HTTP surface (x402 V2 shape + Conduit extensions).
Conduit facilitator base URL
https://conduit-protocol-production.up.railway.app
Every {facilitator} below is this base URL. Probe it live: GET https://conduit-protocol-production.up.railway.app/supported.
Advertises the erc7710 capability + the conduit block: receiptEnforcer, delegationManager, relayBackend, redeemer (the address the work delegation must name), and feeCollector (oneshot-pl only — where the buyer pays gas).
Simulates the redemption on-chain. Returns { isValid, invalidReason }. A bound payment that violates its caveats fails here with the real revert reason.
Submits the redemption through the active relay backend. Returns a jobId + transaction. On oneshot-pl, this relays through 1Shot with gas paid in stablecoin.
Server-Sent Events: the live payment lifecycle (request → permission → settle → settled) for building a live console.
Inbound 1Shot status events (Ed25519-verified against the relayer JWKS) — the source of truth for settlement, forwarded to your webhook.
Build a payment
A payment is an intent-bound redelegation rooted in the user’s ERC-7715 grant. The leaf carries two caveats:
X402ReceiptEnforcer— binds token + recipient + amount + intent hash (89-byte packed terms).IdEnforcer— one-shot: the intent can be redeemed once (replay-proof).
// the leaf delegation: signer → facilitator's redeemer
const caveats = [
{ enforcer: idEnforcer,
terms: abiEncode(["uint256"], [BigInt(intentHash)]) },
{ enforcer: receiptEnforcer, // X402ReceiptEnforcer
terms: packed(["bytes32","address","address","uint128","uint8"],
[intentHash, token, payTo, maxAmount, 0]) },
];
// sign it, encode the chain [leaf, …, root], send as the X-PAYMENT payload.feeCollector, capped at the live quote) and the work delegation above. Even the gas payment is intent-bound. The user’s account is upgraded to a MetaMask Smart Account via EIP-7702 in the same transaction.Roadmap — cross-chain: 1Shot’s relayer also supports multichain settlement (send7710TransactionMultichain) — one relayer call that fans out to several chains, each leg settled and gas paid in USDC on its own chain. So a scout can pick the best venue across chains and the deposit lands wherever wins, with the bounded allowlist enforced per chain. Conduit’s relay seam is built for it; shipping post-hackathon.
In practice this is one call — Conduit’s client picks the right shape from the facilitator’s advertised relayBackend. See lib/payment.ts in the demo for a reference implementation.
Subscriptions
For recurring charges, a service advertises a subscription instead of a one-shot price. Its 402 carries paymentKind: "subscription" and a subscription block:
GET /services/pulse-feed → 402 { accepts: [{ ...,
extra: { paymentKind: "subscription",
subscription: { enforcer, subscriptionId,
periodSeconds, amountPerPeriod } } }] }The buyer signs a service-bound root delegation whose caveat is the X402SubscriptionEnforcer — the user’s own signature binds merchant + exact amount + cadence. 94-byte packed terms:
subscriptionId(bytes32) ++ token(address) ++ recipient(address)
++ amountPerPeriod(uint128) ++ periodDuration(uint32) ++ reserved(uint16)Each period the agent can charge exactly once; a second charge in the same period reverts X402Sub:already-charged-this-period on-chain. Every charge emits X402SubscriptionCharged (subscriptionId, amount, period) for off-chain reconciliation.
On the 1Shot path the strict subscription root can’t fund gas (it only authorizes the exact subscription transfer), so a subscription grant is two bounded user roots: the subscription root + a small gas-fee budget root. Both bounded, both user-approved. See lib/subscription.ts.
Lifecycle. Subscribe once (one signature) → the agent charges once per period → each charge buys a real deliverable → cancel any time. The period is tracked on-chain by the enforcer, so double-charge protection and the “next charge in…” countdown are both derived from the same on-chain truth — not a server clock.
A subscription isn’t just a recurring transfer — each settled charge delivers. Conduit’s demo products (Market Pulse, AI Alpha Daily, DeFi Yield Weekly) each return a live Venice-generated report for the period the charge paid for, attached to the on-chain receipt. The payment and the product settle together: no charge, no deliverable.
Cancelling is disableDelegation(subscriptionRoot). Conduit runs it gaslessly — the relayer executes it from the user’s account, bounded by MetaMask’s AllowedTargets + AllowedMethods enforcers and reimbursed by a small USDC fee — so a fresh account with no ETH can still kill a subscription. Falls back to a direct tx if needed.
Subscriptions are intel; Pay is action. A deliverable carries an “Act on this in Pay →” handoff that deep-links into a matching bounded action — a token-intel report into a SwapAllowlist swap, a yield report into a YieldAllowlist deposit. The report tells you what to do; the enforcer guarantees the agent can only do that.
too much — harmless; it’s a cap, unused allowance is never spent and resets each period. too little — the dapp auto-sizes the allowance to at least the live gas estimate, so a normal charge can’t under-fund; if gas later spikes past the cap, that period’s charge simply reverts on-chain (no funds move, no deliverable) and retries next period. exhausted mid-way — can’t deplete permanently: the allowance refreshes every billing period, so it self-replenishes. A charge either fully settles within budget or fully reverts — never a partial spend.Enforcers
The facilitator relays any ERC-7710 execution — Conduit ships the on-chain caveats that make payments safe. Each binds a delegated transfer so a compromised agent can’t misuse it. The pattern is pluggable: one facilitator, many enforcers.
One-shot, intent-bound payment: binds token + recipient + amount + intent hash; pair with IdEnforcer for replay protection. The standard x402 pay-once flow.
Recurring payment: binds token + recipient + exact amount, charged at most once per period. An agent can renew each period without a new grant — but can’t change the recipient/amount/token or double-charge.
Beyond payments — trading. The same pattern binds DEX swaps, so an agent can trade within bounds it cannot exceed. The facilitator relays these unchanged (its oneshot path is execution-agnostic).
One bounded Uniswap v3 swap: binds router + tokenIn/tokenOut + maxAmountIn + minAmountOut (slippage floor) + recipient. A hijacked agent can’t swap a different token, overspend, accept a worse fill, or redirect the proceeds. Emits SwapBounded.
The dynamic-token version: the user signs a set of output tokens, each with its own floor (router · tokenIn · maxIn · recipient · N · [tokenOut·floor]×N). A scout agent picks the best token from the signed set — choosing a token never gives reach beyond it.
Bounds the ERC-20 approve a swap or deposit needs (token + spender + cap), so the allowance can ride the same 1Shot batch as the action — gas paid in USDC, the user never needs ETH, no standing approval.
Beyond trading — yield. The same pattern binds a lending-pool deposit, so an agent can move funds into yield within a venue set it cannot escape.
One bounded Aave-V3 supply: the user signs a set of yield venues (asset · maxIn · recipient · N · [pool·minAmount]×N). A scout agent picks the best APY from the signed set; a hijacked agent can’t supply into a venue you didn’t approve, overspend, supply a different asset, or redirect the position. Emits YieldAllowed.
are CaveatEnforcer — Conduit-custom caveats on the MetaMask Delegation Framework’s extension point (override beforeHook), enforced by the unmodified DelegationManager on every hop. The allowlist enforcers (swap + yield) are what make “pick the best token/APY” safe: the agent can only ever choose from the set you signed.Bounds & revocation
Every grant — one-shot budget or subscription — is bounded and revocable by the user, not the agent.
Adds a validity window: packed (uint128 after, uint128 before). Past before, redemption reverts TimestampEnforcer:expired-delegation. Without it, a rolling period cap never actually expires on-chain — so Conduit attaches it to make the budget/subscription genuinely die at its deadline.
The kill switch. Gated onlyDeleGator(delegator), so the user’s account sends it — not the agent, not the relayer. Disabling the root cascades: every child redelegation under it dies at once. A direct on-chain tx (needs gas).
Webhooks
Settlement is asynchronous. Register a WEBHOOK_URL and Conduit pushes you a clean event the moment a payment confirms — on any relay path.
POST {your WEBHOOK_URL}
{
"type": "conduit.settlement",
"jobId": "…",
"status": "confirmed", // | "failed"
"success": true,
"txHash": "0x…",
"error": null
}Conduit consumes 1Shot’s Ed25519-signed webhooks (verifying them against the relayer’s JWKS), then forwards this simple event to you. You never touch the relayer, the chain, or signature verification.
Addresses
Base mainnet (live). The full enforcer family is deployed and verified on both networks; these addresses reflect the chain this app is configured for.