Signed mandate documents plus a client-side scheduler that pays per run over x402 and collects signed run reports. No subscriptions, no stored cards, no server-side pulls.
git clone https://github.com/nirholas/x402-recurring && cd x402-recurring npm install && npm run dev
Every paid route answers with a dual-rail 402. The accepts array carries one EVM entry and one Solana entry; your client (or the checkout modal) picks whichever wallet it has. Each rail settles through its own facilitator — no single one handles both.
base-sepolia / base0x40252CFDF8B20Ed757D61ff157719F33Ec332402x402.org/facilitatorsolana-devnet / solanaWwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwWfacilitator.payai.network/execute; server quotes the mandate's exact price on both railsThe server never pulls funds. Your scheduler pays each run when it happens — cancel by simply not paying again. Budget caps (maxRuns, price ceiling, expiry) live in the signed mandate.
| Route | Price | Returns |
|---|---|---|
POST /mandates | free | Signed mandate document |
POST /execute/:mandateId | $0.005 (per mandate — its own `pricePerRun`) | Signed run report: run number, budget state, and the task artifact |
GET /mandates/:id | free | Mandate status snapshot |
GET /mandates | free | Mandate summaries |
POST /verify | free | `{ valid: true | false }` |
GET /health | free | `{ ok: true }` |
import { wrapFetchWithPayment } from "x402-fetch";
import { privateKeyToAccount } from "viem/accounts";
const payFetch = wrapFetchWithPayment(fetch, privateKeyToAccount(process.env.PRIVATE_KEY));
const mandate = await (await fetch("http://localhost:4021/mandates", {
method: "POST", headers: { "content-type": "application/json" },
body: JSON.stringify({ task: { type: "heartbeat" }, pricePerRun: "$0.005", maxRuns: 5 })
})).json();
const report = await (await payFetch(
`http://localhost:4021/execute/${mandate.mandateId}`, { method: "POST" }
)).json(); // signed run report — the purchased artifact
/.well-known/x402 — machine-readable manifest, both networks per resource (indexable by x402scan.com, the x402 Bazaar, agentic.market)