x402-foundation

Activity

Stars and mentions · Last 30 days, Oct 6 – Nov 4

GitHub stars77
Mentions69
02468Oct 6Oct 20Nov 4
UTC days · repositories x402-foundation owns1 repository

Top repositories

x402-foundation’s repositories ranked by new stars, as on trending.

Loading

Contributes to

Repositories outside x402-foundation’s account where x402-foundation opened or reviewed pull requests in the past 365 days.

Who noticed x402-foundation

Everyone who starred or forked x402-foundation’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

67posts
Nov 50 posts
  1. The x402 Foundation repo brings together the specification, reference SDKs and examples for building payments into the web. Explore the code, open an issue or contribute a pull request: x402-foundation/x402 t.co

    22 likes · 7 reposts · 1,273 views
  2. Coinbase’s x402 Bazaar Count Fell From 106,068 to 28,135. What Happened? Originally published at forgemesh.io. On October 31, our monitor recorded 106,068 resources in Coinbase’s x402 Bazaar. Eight hours later, the reported count was 28,135. The obvious question: did someone wipe the directory? We don’t know. The data shows a sharp change in the count reported by the API; it does not establish why the number changed or which entries were affected. What we observed Our scheduled collector recorded these reported totals (all times UTC): October 31 at 12:15, 107,100; October 31 at 20:15, 106,068; November 1 at 04:15, 28,135; November 1 at 12:15, 28,266; November 1 at 20:15, 49,328; November 2 at 04:15, 64,865; and November 2 at 12:15, 75,842. A separate read-only request to Coinbase’s public discovery API reported 81,315 at 16:22 UTC on November 2, and 81,573 at 16:29 UTC. Counts can change after publication. Between the October 31 evening and November 1 morning snapshots, the reported count fell by 77,933, nearly 74%. The eight-hour interval brackets when our monitor saw the change; it does not tell us the exact minute it began. These are listings reported by one facilitator’s catalog, not counts of companies, servers, customers, transactions, or every service in the x402 ecosystem. Why we can’t call it a wipe A discovery catalog is a view of resources. Its reported total can change for several reasons: resources may expire, the operator may change filters or indexing, data may be reprocessed, or the count itself may be calculated differently. We have not confirmed which, if any, explains this event. Our collector records the API’s reported total but fetches at most 40,000 rows in a run. When the reported total was above that cap, we did not independently enumerate the whole catalog. Our database retains only first- and most-recent-seen markers, so we cannot reconstruct a complete list of entries present in each earlier snapshot. The catalog may also change while pages are being fetched. At 04:15 on November 1, the first page reported 28,135 while the collector fetched 28,143 rows over the run. An API total and a paginated crawl are not necessarily an atomic snapshot. The defensible finding is narrow: Coinbase’s discovery API reported a major fall in its resource total, followed by an increase. The cause and the identities of affected listings remain unverified. What builders can do Keep a list of the canonical routes you expect to be discoverable. Check them against the directory on a schedule, and record timestamps and missing entries. Probe each endpoint separately. A missing catalog entry does not itself prove an API or its payment flow is down. Check discovery metadata and the payment path before spending money to refresh entries, and verify whether any refresh restores the intended resource. Give buyers another way to find and understand your service: clear documentation, machine-readable descriptions, and a stable direct URL. The x402 Bazaar specification describes discovery APIs as optional and leaves storage and indexing details to facilitators. What we’re watching next We’ll look for a public explanation and compare route-level observations over time. Establishing what happened would require a reliable before-and-after membership comparison, an explanation from the operator, or both. For now, we’re calling this a listing-count fluctuation, not a confirmed server wipe. If you run x402 services, check your own routes and save the results so the next count change can be investigated at the resource level. Method: ForgeMesh collector snapshots of Coinbase CDP’s discovery endpoint, October 30–November 2, 2026; separate API checks at 16:22 and 16:29 UTC on November 2. Totals are API-reported; larger crawls were capped at 40,000 fetched rows.

  3. Facilitator: facilitator.bursar.world Transaction: robinhoodchain.blockscout.com Support in the upstream x402 reference asset tables is proposed in x402-foundation/x402 #3770: x402#3770

    3 likes · 195 views
  4. Why does my x402 endpoint fail? A debugging checklist --- title: "Why does my x402 endpoint fail? A debugging checklist" published: true description: "Five steps between the agent, your server and the facilitator: what each failure looks like, the fix, and a free tool for each." tags: x402, webdev, api, payments canonical_url: fizzl.eu --- When "the x402 payment fails", one of five steps broke, and each one fails in its own way. Find the step first, then the fix. In the order a paying agent goes through them: | Step | What the agent sees when it breaks | Check it with | |---|---|---| | 1. The URL answers 402 | 404, 401, a login page, or 200 for free | curl -i with the listed method | | 2. The 402 is one a client accepts | The client throws before it signs | A free 402 check | | 3. The payment reaches your server | A new 402 right after paying, nothing settled | Your log: is PAYMENT-SIGNATURE there? | | 4. The facilitator verifies and settles it | A 402 with an error reason such as insufficient_funds | The errorReason; the facilitator's GET /supported | | 5. Your route answers after settling | Paid, then a 400, 404 or 500 | PAYMENT-RESPONSE and the transaction on-chain | 1. Does the URL answer 402? Call it the way the listing says, with no payment: curl -i https://api.example.com/v1/price?symbol=BTC. You want 402 and a PAYMENT-REQUIRED header. If not: - 404 or 405: the route takes another method than the listing says (often POST, listed as GET). - 401 or a login page: an API-key check runs before the paywall. In x402 the payment is the authorization: put the payment middleware first. - 200 with the real answer: the payment middleware is registered after the handler, or its route key doesn't match. - 400 "missing parameter": input validation runs before the paywall. Let a request without input reach the 402. Older x402 SDK versions also answered a HEAD on a paid GET route with the paid answer, for free (x402-foundation/x402#3796). Update @x402/core and your framework adapter, or refuse HEAD on paid routes. 2. Is the 402 one a client accepts? PAYMENT-REQUIRED is base64-encoded JSON. Decode it and check: - resource.url is the exact public https URL. Behind Render, Fly, Railway or Heroku the proxy ends TLS, so Express builds an http:// URL unless you set app.set("trust proxy", 1). It's the most common problem we see: 2,009 endpoints in one daily scan. - network is a CAIP-2 id such as eip155:8453, and at least one option is a mainnet. - asset is the token's contract address, not a name (on Stellar: the USDC token contract, not "USDC"). - payTo can receive the asset (a Solana account that exists, an Algorand address opted in to USDC, an XRPL trust line). - maxTimeoutSeconds gives the agent time to sign and send. - The price matches your listing. Careful agents stop when the 402 asks more. 3. Does the payment reach your server? A fresh 402 with no error reason usually means your server never saw the payment: - Header name: x402 v2 clients send PAYMENT-SIGNATURE; old v1 clients (x402-fetch, x402-axios) send X-PAYMENT. A v2-only server treats a v1 payment as none. - CORS: a browser can't read PAYMENT-REQUIRED unless the 402 lists it in Access-Control-Expose-Headers, and can't send PAYMENT-SIGNATURE unless the preflight allows it in Access-Control-Allow-Headers (x402 HTTP transport spec). - A proxy or cache that strips unknown headers or replays the first 402. 4. Does the facilitator verify and settle it? The 402 or PAYMENT-RESPONSE then carries an error reason from the spec: | Error reason | Usually means | |---|---| | insufficient_funds | The payer lacks the asset on that network (or your price is in the wrong unit: 10000 is $0.01 for 6-decimal USDC) | | invalid_network, unsupported_scheme | Your facilitator doesn't handle it; GET /supported lists what it settles | | invalid_exact_evm_payload_recipient_mismatch | payTo changed between the 402 and the payment | | …_authorization_valid_before / …_valid_after | Expired or not yet valid: timeout too short, or a clock off | | invalid_exact_evm_payload_signature | Wrong token name/version in extra, or another chain id | | invalid_payment_requirements | The terms changed between the 402 and the payment | | unexpected_settle_error | The facilitator's own problem (RPC, gas, timeout) | 5. Does your route answer after settling? The worst case for a buyer: paid, then an error. In one of our weekly test buys, 3 of 27 purchases ended that way. Validate input before you settle, so a request you can't answer is never charged, and declare a Bazaar example that actually works. When a buyer says they paid and got nothing, ask for the PAYMENT-RESPONSE header and look up the transaction it points to. Free tools, by step - Steps 1–2 (and readiness for 3–5): x402 Doctor's web check reads your 402 the way a paying agent does and gives the fix as code; also a CLI (npx github:Fizzl13/x402-doctor <url>) and a GitHub Action. Disclosure: we make it. - Steps 1–2 for the CDP Bazaar: Coinbase's free validate API, POST https://api.cdp.coinbase.com/platform/v2/x402/validate. - Step 2 in CI: x402lint. - Step 4: your facilitator's GET /supported and its logs. - Step 5: x402 Doctor's payment-proof check reads a PAYMENT-RESPONSE and shows the transaction on-chain. The full guide, kept up to date: fizzl.eu.

  5. Discuss+ The New AI Gold Rush: How to Make Money from AI Bots Scanning Your Content The next generation of online businesses may not compete only for human attention. They may compete to become the services that AI agents discover, trust and pay to use.🤑 !Image description A 2-Minute Look at the Bot Economy We talk a lot about AI bots reading websites, scraping content and discovering software. But here is a more interesting question: !Image description What happens when AI agents stop being visitors and start becoming customers? Thanks for support.. Release: "Sentinel-IR-MCP v0.2.2 on GitLab" (gitlab.com) Package: "sentinel-ir-mcp@0.2.2 on npm" (npmjs.com) There are three emerging ways to make money from this shift. 1. Get discovered by AI Your open-source project, API or technical content becomes discoverable to AI-powered tools and agents. This can bring developers and potential customers to your project. But visibility is only a marketing channel. A bot reading your article does not automatically generate revenue. 2. Charge bots for reading your content This is no longer just a theoretical idea. "Cloudflare Pay Per Crawl" (developers.cloudflare.com) allows website owners to set prices for AI crawler access. There is one important detail: as of October 2026, the feature is still in closed beta. The interesting business question is whether AI companies will actually pay for access to valuable information. 3. Sell services directly to AI agents This is where things get even more interesting. Imagine an AI agent that needs a code analysis, a data query or a specialized API result. Instead of creating an account, managing an API key or asking a human to pay, it could discover a price, authorize a payment and receive the service automatically. Two protocols worth watching: !Image description - "x402" (x402-foundation/x402) enables payments directly through HTTP requests. - "MPP (Machine Payments Protocol)" (stripe.com) is another approach to machine-to-machine payments, developed by Stripe and Tempo. And an important distinction: MCP gives agents access to tools. MPP and x402 can provide the payment mechanism for using them. Reality check: Is this already a real economy? There is actual activity, but we should be careful with the numbers. "TRM Labs published an analysis in September 2026" (trmlabs.com). It identified approximately $52.7 million in x402 settlements. However, after filtering the data, its estimate of activity that actually appeared agentic was only 0.6% to 7.5% of the screened commerce. So the payment infrastructure exists. The real agent economy is still developing. The question is not whether bots can read your website. The question is whether you can build something useful enough that an AI agent will discover it, understand its price, pay for it and use it. That could mean paid data, API calls, MCP tools, content access or specialized services. What do you think will become the first sustainable business model of the AI agent economy? x402-trust.com Will agents pay for information, software tools, APIs or something we haven't even considered yet? And more importantly: have you seen an AI agent actually pay for a service without a human completing the purchase? #AI #Agents #AgenticAI #x402 #MCP #OpenSource

    3 reactions
  6. Making contributions x402#3943

    3 likes · 280 views
  7. エージェントの財布の中身を開ける — x402の署名と、使いすぎを止める場所 AI エージェントが勝手に払う仕組みで、一番こわいのは「止まらないこと」だ。1 回 1 セントでも、ループすれば財布は空になる。 テストネットで実測した結論は 3 つある。SDK は何も指定しなくても、1 回 $1 の上限をかけていた。累計の上限は SDK に無く、自分で書いた。決済に失敗した署名は死なず、curl で再送したら払えた。 第 1 回で、払う側を後回しにした。今回はそこを開ける。署名の中身をデコードして読み、上限をどこに置けば止まるかを調べた。 連載「AIエージェントに財布を持たせる」の第 2 回だ。 ! 連載の記事一覧 第 1 回:HTTP 402は29年「予約済み」のまま — x402をNext.jsで動かす 第 2 回:エージェントの財布の中身を開ける — x402の署名と、使いすぎを止める場所(この記事) 第 3 回:守る対象は台帳ではなく、鍵とコードだった — x402 の財布を MCP サーバーに出して sandbox で囲む 第 4 回:JPYC 編(準備中) 402 を受けたら上限を確かめ、署名して再送するクライアントを作った 作ったのは pnpm buy <url> で動くクライアントだ。402 を受けたら支払い条件を読み、上限に収まるときだけ署名して、同じリクエストを送り直す。 このクライアントが止める場所は 2 か所ある。1 回あたりの上限(SDK の既定は $1)と、累計の上限(自前)だ。どちらも署名より前に効く。 コードは agent-payments-lab の x402-02 タグにある。売り手の API は第 1 回のものを Vercel に置いてあり、paid-api-flax.vercel.app が 402 を返す。curl だけで試せる。 前提は第 1 回のまま、パッケージは 2.28.0 に固定した すべてテストネット(Base Sepolia、eip155:84532)だ。USDC に金銭的価値はなく、1 回の支払いは 0.01 USDC である。USDC の値動きや投資の話は一切しない。 実費は 0 円だった。テストネットの USDC は faucet で無料、売り手の公開 URL は Vercel の無料枠に置いている。 ウォレットは連載専用の新規生成で、実資産は入れていない。 @x402/fetch @x402/core @x402/evm @x402/next はすべて 2.28.0、viem は 2.57.7。いずれも 2026 年 10 月 15 日に確認した版で、第 1 回と同じだ。 売り手は第 1 回の /api/weather をそのまま使う。失敗の検証用に、必ず 500 を返す /api/flaky と、必ず throw する /api/throw を足した。 買い手に ETH は要らない。第 1 回で確かめた事実で、今回も買い手の ETH は 0 のままだった。理由は署名の節で書く。 財布は口座ではなく印鑑で、押した書類は期限まで誰でも使える ここでいう財布は、秘密鍵のことだ。残高を持つ入れ物ではない。残高は USDC のコントラクトが、アドレスごとに記録している。 秘密鍵からアドレスが決まる。署名は「この鍵の持ち主が、この内容に同意した」という証拠になる。印鑑に近い。印鑑自体にお金は入っていないが、押された書類は効力を持つ。 だから、エージェントに財布を持たせるとは、印鑑を持たせることだ。何に押してよいかを、押す前に決めておく必要がある。 比喩はもう少し先まで効く。押した書類は、期限が切れるまで、拾った人も出せる。持参人払いの小切手に近い。署名してから止めようとしても遅い、という話は、後の実測でそのまま出てくる。 署名の中身は 6 つの欄で、金額も宛先もそこに固定される pnpm buy は、送る直前の PAYMENT-SIGNATURE ヘッダーをデコードして表示する。実測の結果だ。 { "x402Version": 2, "payload": { "authorization": { "from": "0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673", "to": "0x621279161e951eB55195FB872e46CE47C6925506", "value": "10000", "validAfter": "0", "validBefore": "1792042709", "nonce": "0x8508a708b055ac45b1d1e881303982e6075b56003e44ff632695faeb50679619" }, "signature": "0xf94f3f739217578c73b8e7063fd054bdfd40cbef50f5d20a5c6f2f599d2f747c3807539e29f981e562604231efd8bcd9c412f5efd6388017e873e0fe11cc7c661b" }, "resource": { "url": "localhost", "description": "Weather data", "mimeType": "" }, "accepted": { "scheme": "exact", "network": "eip155:84532", "amount": "10000", "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", "payTo": "0x621279161e951eB55195FB872e46CE47C6925506", "maxTimeoutSeconds": 300, "extra": { "name": "USDC", "version": "2" } } } payload.authorization が署名の対象だ。これは EIP-3009 の TransferWithAuthorization で、6 つの欄がある。 from は払う人、to は受け取る人、value は金額だ。10000 は USDC の小数 6 桁で 0.01 にあたる。validAfter と validBefore は有効期間で、nonce は使い捨ての番号だ。 2.28.0 の実装では、validAfter は固定で "0"、validBefore は署名した時刻に maxTimeoutSeconds(今回は 300)を足した値だ。nonce は暗号乱数の 32 バイトである。 この実測では、validBefore の 2026-10-15 05:38:29 UTC から 300 秒を引くと 05:33:29 で、Basescan 上の tx の時刻 05:33:32 と合う。 なお仕様書の例は validAfter が現在時刻付近になっていて、実装とは食い違う。この記事は実測値を載せる。 署名は EIP-712 の型つきデータに対して作られる。署名に混ぜる domain は、トークンの名前(USDC)、版(2)、チェーン ID(84532)、USDC のコントラクトのアドレスだ。名前と版は、402 の accepts[].extra に入っている。ここまでは @x402/evm の実装を読んで確かめた。 ここから、ファシリテーターが何もいじれない理由が決まる。署名は to と value を含む。ファシリテーターが宛先や金額を書き換えると、USDC のコントラクトが署名の検証に失敗する。仕様書(exact スキームの EVM 版)も、ファシリテーターは金額も宛先も変更できないと書いている。 ETH が要らない理由も同じ場所にある。買い手が作るのは署名だけで、チェーンに送るトランザクションはファシリテーターが作る。ガスを払うのもファシリテーターだ。 Basescan で今回の tx を見ると、From が買い手ではなくファシリテーターになっている(第 1 回を参照)。 Status の Success、From(0xd407…)、ERC-20 Tokens Transferred の 0.01 を見る。買い手は From に出てこない。 実装は buy.ts の 90 行で、フックのために client を手組みした クライアントは apps/agent-client/src/buy.ts の 1 ファイルだ。tag x402-02 のコードをそのまま載せる。 本文には import と引数、累計ファイル、client の 3 つを載せ、spy と実行部は折りたたんだ。 apps/agent-client/src/buy.ts // Usage: pnpm buy <url> [--max-per-call <usd>] [--max-total <usd>] import { x402Client, wrapFetchWithPayment, decodePaymentResponseHeader } from "@x402/fetch"; import { decodePaymentRequiredHeader, decodePaymentSignatureHeader } from "@x402/core/http"; import { ExactEvmScheme } from "@x402/evm"; import { privateKeyToAccount } from "viem/accounts"; import { readFileSync, writeFileSync } from "node:fs"; const args = process.argv.slice(2); const opt = (name: string, def: string) => { const i = args.indexOf(name); return i >= 0 ? args[i + 1] : def; }; const url = args.find((a, i) => !a.startsWith("--") && !args[i - 1]?.startsWith("--")); if (!url) { console.error("usage: pnpm buy <url> [--max-per-call <usd>] [--max-total <usd>]"); process.exit(2); } const maxPerCall = opt("--max-per-call", "0.01"); const maxTotalAtomic = BigInt(Math.round(Number(opt("--max-total", "0.05")) * 1e6)); // USDC: 6 decimals --max-total は USD で受けて、USDC の最小単位(6 桁)の整数に直す。以後の比較はすべてこの整数で行う。 累計は、ファイルに持つ。SDK に累計の上限が無いためだ(次の節で書く)。 apps/agent-client/src/buy.ts // Cumulative spend lives in a file so it survives across runs (the SDK has no cumulative cap). const SPEND_FILE = new URL("../.x402-spend.json", import.meta.url); const readSpent = (): bigint => { try { return BigInt(JSON.parse(readFileSync(SPEND_FILE, "utf8")).spentAtomic); } catch { return 0n; } }; const usdc = (atomic: string | bigint) => (Number(atomic) / 1e6).toFixed(6); const USDC_BASE_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e"; const account = privateKeyToAccount(process.env.BUYER_PRIVATE_KEY as 0x${string}); 本体は x402Client だ。 wrapFetchWithPaymentFromConfig は設定を渡すだけで内部で client を作るので、onBeforePaymentCreation のようなフックを後から付けられない。2.28.0 のソースで確かめた。そこで x402Client を自分で組み、wrapFetchWithPayment に渡した。 apps/agent-client/src/buy.ts const client = new x402Client() .register("eip155:84532", new ExactEvmScheme(account)) // SDK default is "$1" per payment even if you set nothing. Set it explicitly and lower. .setSpendControls({ maxAmountPerPayment: $${maxPerCall} }) .onBeforePaymentCreation(async ({ selectedRequirements }) => { // The total counts USDC atomic units only (6 decimals), so refuse any other asset. if (selectedRequirements.asset.toLowerCase() !== USDC_BASE_SEPOLIA.toLowerCase()) { return { abort: true, reason: max-total counts USDC (6 decimals) only; got asset ${selectedRequirements.asset} }; } const spent = readSpent(); const amount = BigInt(selectedRequirements.amount); if (spent + amount > maxTotalAtomic) { return { abort: true, reason: max-total ${usdc(maxTotalAtomic)} USDC would be exceeded (spent ${usdc(spent)} + ${usdc(amount)}) }; } }) // Count at signing time, not at 200: a signed authorization stays spendable by anyone // until validBefore, so signing is the worst-case commitment. Over-counts on 5xx; fine for a cap. .onAfterPaymentCreation(async ({ selectedRequirements }) => { writeFileSync(SPEND_FILE, JSON.stringify({ spentAtomic: (readSpent() + BigInt(selectedRequirements.amount)).toString() }) + "\n"); }); register で、eip155:84532 だけを扱うと決める。登録していないネットワークの支払い条件は、選択の段階で落ちる。setSpendControls は 1 回あたりの上限だ。 onBeforePaymentCreation は署名の前に呼ばれ、abort: true を返すと署名せずに例外になる。onAfterPaymentCreation は署名の後に呼ばれる。 onBeforePaymentCreation の先頭には、資産を USDC に限るガードを 1 つ入れてある。累計の単位が USDC の 6 桁に固定されているためだ。SDK の既定でも USDC 以外は先に弾かれるので、二重の守りになる。 spy と実行部(buy.ts の残り) 実際に流れるものを見るために、spy を内側の fetch として挟んである。 apps/agent-client/src/buy.ts // Spy on the inner fetch: shows exactly what goes on the wire. const spy: typeof fetch = async (input, init) => { const req = input instanceof Request ? input : new Request(input, init); const sig = req.headers.get("PAYMENT-SIGNATURE"); if (sig) { const p = decodePaymentSignatureHeader(sig); console.log("-> request with PAYMENT-SIGNATURE:"); console.log(JSON.stringify(p, null, 1)); const a = (p.payload as any).authorization; if (a) console.log( authorization: ${usdc(a.value)} USDC ${a.from} -> ${a.to}, validBefore ${new Date(Number(a.validBefore) * 1000).toISOString()}); } else console.log(-> ${req.method} ${req.url}); const res = await fetch(req); console.log(<- ${res.status} payment headers: ${[...res.headers.keys()].filter((k) => k.includes("payment")).join(", ") || "(none)"}); const pr = res.status === 402 && res.headers.get("PAYMENT-REQUIRED"); if (pr) { const d = decodePaymentRequiredHeader(pr); console.log( error: ${d.error}); console.log( accepts: ${JSON.stringify(d.accepts)}); } return res; }; console.log(buyer: ${account.address} max-per-call: $${maxPerCall} max-total: ${usdc(maxTotalAtomic)} (spent so far: ${usdc(readSpent())})); try { const res = await wrapFetchWithPayment(spy, client)(url); console.log("status:", res.status); console.log("body:", await res.text()); const h = res.headers.get("PAYMENT-RESPONSE"); if (h) { const d = decodePaymentResponseHeader(h); console.log("payment-response:", JSON.stringify(d)); console.log("basescan:", https://sepolia.basescan.org/tx/${d.transaction}); } process.exit(res.status === 200 ? 0 : 1); } catch (e) { console.error("blocked:", e instanceof Error ? e.message : e); process.exit(2); } wrapFetchWithPayment は、2 回目のリクエストを Request オブジェクトで fetch に渡す。spy はその PAYMENT-SIGNATURE を読み、デコードして出す。 402 のときは PAYMENT-REQUIRED の error と accepts も出す。前節の JSON はこの出力だ。 終了コードは、200 なら 0、200 以外なら 1、署名前に止まったときは 2 だ。 1 つ矛盾がある。spy は有効な署名を stdout に出している。署名は 300 秒間、持参人払いの小切手と同じだ。それをログに書くのは、小切手の現物をログに貼るのと変わらない。デバッグ用だから出した。本番では出さない。 使いすぎを止める仕組みは SDK にほぼ揃っていて、累計だけが無い なぜ累計が本命なのか。Keyrock のレポートは、x402 の支払い 1.76 億件のうち 76% が 30 セント未満だと書く(Keyrock「Who Pays the Agent?」、2026 年 10 月 15 日に確認)。 同じ文書は、約 30 セントの固定手数料のもとでは 1 ドル未満の支払いは採算が合わない(原文は sub-dollar payments uneconomical)とも言う。 Keyrock は 1.76 億件を x402 の支払いとも、エージェントの決済とも呼んでいる。すべてがエージェント由来かは、この文書から確かめられない。本文に日付はないが、メタデータ上の公開日は 2026-05-21 で、集計期間の記載はなかった。 1 回の支払いが小さいなら、1 回あたりの上限はほとんど効かない。効くのは累計だ。その前提で、SDK にある止め方を数えた。 何を制限するか SDK にあるか 既定値 このコードでの設定 1 回の金額 あり(spendControls.maxAmountPerPayment) $1 $0.01(--max-per-call で変更) 許可するアセット あり(allowedAssets) 既定のアセット(USDC など)だけ 既定のまま。USDC 限定の自前ガードを追加 許可するネットワーク あり(register したものだけ) 登録しなければ通らない eip155:84532 だけ 払う先(payTo) 専用のオプションは無い(policies で自前) なし 入れていない 累計 なし なし 自前(.x402-spend.json とフック)。既定は 0.05 USDC SDK を読んで、1 つ驚いた。new x402Client() と書くだけで、1 回あたり $1 の上限が有効になっている。spendControls.maxAmountPerPayment の既定値が "$1" なのだ(@x402/core の client のソース)。 第 1 回の pay.ts は上限を指定していなかったので、$1 を超える請求は、署名の前で断られる状態だった。超える請求は来なかったので、実際に断られたことはない。 つまり、第 1 回の pay.ts をそのままループで回すと、0.01 USDC の請求は $1 の上限に一度も当たらず、通り続ける。第 1 回の時点で買い手には 19.99 USDC があった。0.01 ずつなら、1,999 回で空になる計算だ。実際に回したわけではない。 だから累計は自分で書いた。ソースに、累計や日次の予算にあたる語は見つからなかった。onBeforePaymentCreation で止めて、onAfterPaymentCreation で加算する形だ。 以下のログは、pnpm の失敗表示(ELIFECYCLE など)や basescan: の行、署名の JSON を省略している。 実測の結果。--max-per-call 0.005 で 0.01 USDC の API を呼ぶと、1 回目の 402 を受けた後、署名せずに止まった。 $ pnpm buy localhost --max-per-call 0.005 buyer: 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 max-per-call: $0.005 max-total: 0.050000 (spent so far: 0.040000) -> GET localhost <- 402 payment headers: payment-required (error と accepts の行は省略した) blocked: Failed to create payment payload: All payment requirements were rejected by spendControls.maxAmountPerPayment ($0.005, including USDC). (以降の対処の案内は省略した) exit code: 1 # pnpm 経由のため。tsx を直接叩くと 2 [balance after (+8s)] 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 ETH 0 USDC 19.91 PAYMENT-SIGNATURE つきのリクエストは出ていない。買い手の残高は 19.91 のまま動かなかった。 累計の方は --max-total 0.02 で同じ API を 3 回呼んだ。直前に .x402-spend.json を 0 に戻してある(理由は後の節で書く)。1 回目と 2 回目は 200 で、3 回目は 402 を受けた後に止まった。3 回目のログだ。 $ pnpm buy localhost --max-total 0.02 # run 3 buyer: 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 max-per-call: $0.01 max-total: 0.020000 (spent so far: 0.020000) -> GET localhost <- 402 payment headers: payment-required (error と accepts の行は省略した) blocked: Failed to create payment payload: Payment creation aborted: max-total 0.020000 USDC would be exceeded (spent 0.020000 + 0.010000) exit code: 1 # pnpm 経由のため 1。tsx 直接なら 2 [balance after (+8s)] 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 ETH 0 USDC 19.89 0x621279161e951eB55195FB872e46CE47C6925506 ETH 0 USDC 0.11 spend file: {"spentAtomic":"20000"} 買い手の残高は、この 3 回の前の 19.91 から 19.89 になった。減ったのは 0.02 で、3 回目は払っていない。買い手のアドレスの Token Transfers でも、直近の 2 件が 1 回目と 2 回目で、3 件目は無い。 0xc587…(1 回目)と 0x50ad…(2 回目)が最上段の 2 件。3 回目の行は無い。下の 20 は faucet からの入金。 累計を数えるのは、200 が返った後ではなく、署名した時点にした。署名した時点が、最悪の場合に払うことが確定する時点になるからだ。 副作用がある。5xx で課金されなかった回も、累計に入る。実際、累計上限の実験の直前に .x402-spend.json は 0.04 だったが、払われたのは 0.02 だけだった。flaky と throw の 2 回が 500 だったためだ。上限としては安全側に倒れる。ただし、残りの予算が実際より少なく見える。 このコードには限界もある。累計の単位は USDC の 6 桁に固定したままだ。複数の資産を許すなら、資産ごとに単位を揃える必要がある。 ハンドラが失敗したら課金されない — ソースと実測が一致した 売り手の withX402 は、ハンドラのレスポンスが 400 以上なら、決済を確定しない。@x402/next 2.28.0 の index.js で、該当の箇所を抜粋する(205〜224 行付近、抜粋。... は省略。// の行は筆者のコメント)。 @x402/next/dist/esm/index.js async function handleSettlement(httpServer, response, paymentPayload, ...) { if (response.status >= 400) { const cancelSettlement = await cancellationDispatcher.cancel({ reason: "handler_failed", responseStatus: response.status }); ... return response; // 筆者のコメント: settle せずハンドラのレスポンスをそのまま返す } ハンドラが例外を投げた場合は、427〜451 行付近の catch に入る。 throw の場合のソース抜粋 @x402/next/dist/esm/index.js try { handlerResponse = await routeHandler(request); } catch (error) { const cancelSettlement = await result.cancellationDispatcher.cancel({ reason: "handler_threw", error }); if (!result.beforeHandlerSettlement && !cancelSettlement) { throw error; // 筆者のコメント: exact ではここで再 throw } 再 throw する条件は、!beforeHandlerSettlement && !cancelSettlement だ。 exact スキームでは、ハンドラの前に決済を確定する処理が無く、cancel も何も返さない。この条件が成り立って、例外はそのまま再 throw される。Next.js が 500 を返し、決済の確定は走らない。cancel() の中身までは追っていない。 実測する。/api/flaky は 500 を返す。 $ pnpm buy localhost [balance before] 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 ETH 0 USDC 19.91 0x621279161e951eB55195FB872e46CE47C6925506 ETH 0 USDC 0.09 -> GET localhost <- 402 payment headers: payment-required -> request with PAYMENT-SIGNATURE: (署名の JSON は省略した) <- 500 payment headers: (none) status: 500 body: {"error":"boom"} exit code: 1 [balance after (+8s)] 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 ETH 0 USDC 19.91 0x621279161e951eB55195FB872e46CE47C6925506 ETH 0 USDC 0.09 /api/throw は例外を投げる。ログの形は flaky とほぼ同じで、違いは body: が空なことだけだ。Next.js の 500 は本文を持たない。残高は前後とも 19.91 のままだった。 どちらも、残高は前後で変わらない。PAYMENT-RESPONSE ヘッダーも付いていない。第 1 回で「次回測る」と書いた件の答えは、課金されない、だ。 注意が 2 つある。署名が検証を通ってからハンドラが走るので、失敗のときも時間はかかる。dev サーバーのログでは、/api/flaky の 500 は 307ms だった。そして、実機で確かめたのは 500 と throw だけで、4xx は読んだだけで試していない。 予定していなかったのは決済の失敗で、裏づいたのは署名が生き残るという推論だ 時系列では、この節の実行は累計の実験より前だ。第 1 回の 0.01 を含めて決済は計 11 回、買い手は 20.00 から 19.89、売り手は 0.11 で帳尻が合う(第 1 回の時点の 19.99 から 19.91 までは、この間の 8 回の決済の分だ。台帳は tag x402-02 の docs/notes/x402-02-run.md の末尾)。 失敗系の検証の途中で、予定していなかったことが起きた。pnpm buy が 402 のまま終わったのだ。2 回目の計測の最初の実行でも、1 回目の計測でも起きた。 <- 402 payment headers: payment-response status: 402 body: {} payment-response: {"success":false,"errorReason":"invalid_exact_evm_transaction_failed","errorMessage":"…(省略)… replacement transaction underpriced …","transaction":""} [balance after (+8s)] 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 ETH 0 USDC 19.93 errorMessage は長いので省略した(payer と network の欄も省いた)。末尾に replacement transaction underpriced とあり、ファシリテーターが tx を送る段階で失敗している。原因は、ファシリテーター側の送信ウォレットの nonce の衝突だと見ているが、これは推測だ。同じ署名が後で通ったので、こちらの署名や残高が原因ではない。買い手の残高は減っていなかった。 weather の支払いは、1 回目と 2 回目の計測を合わせて 10 回あり、このうち 2 回がこの失敗だった。 そこで、署名の JSON を base64 に詰め直し、同じ PAYMENT-SIGNATURE を curl で送ってみた。 $ curl -i localhost -H "PAYMENT-SIGNATURE: <最初の実行の署名 JSON をコンパクトに base64 化したもの>" HTTP/1.1 200 OK ... {"report":{"weather":"sunny","temperature":70}} [balance after (+8s)] 0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673 ETH 0 USDC 19.92 200 が返り、買い手の残高は 19.93 から 19.92 になった。署名は決済に成功するまで生きていて、validBefore までは再送できる。ソースを読んで立てた推論が、実機で裏づいた。 署名の一生を図にすると、次のようになる。 裏を返すと、署名を持っている誰もが、期限内なら使える。to と value は署名で固定されているので、他の宛先へは動かせない。だが「払うと決めた覚えのない回で払われる」ことは、あり得る。累計を署名の時点で数える理由はこれだ。 取り消す手段は、EIP-3009 に cancelAuthorization として用意されている。未使用の nonce を使用済みにするもので、署名の持ち主が tx を送る。買い手が自分で送るなら ETH が要る。今回は試していない。何もしなければ、署名は validBefore(今回は署名から 300 秒)まで有効なままだ。 支払い済みの署名を再送するとどうなるかも試した。別の署名 B を 200 で使った後、同じ署名 B を curl で送り直した(1 回目の計測で取ったもの)。 HTTP/1.1 402 Payment Required cache-control: no-store ... {} payment-response をデコードした。 { "success": false, "errorReason": "invalid_exact_evm_transaction_failed", "payer": "0x62f9ECa8CC6332972705e7D5bEdc9f776CFdF673", "transaction": "0x6de97dc7e550c172edf21fea0a97af75101885f958e29418b52c1297944f75c1", "network": "eip155:84532" } 期待していたのは invalid_exact_evm_nonce_already_used だった。出なかった。検証は通り、ファシリテーターが tx を送り、その tx がオンチェーンで revert した。receipt の status は 0x0 だった。Basescan では、次のように見える。 Status の Fail と、理由の FiatTokenV2: authorization is used or canceled を見る。 ガスはファシリテーターが払い、買い手の残高は動かなかったので、二重払いにはならない。 なぜ検証が通ったのかは、確定していない。事実として書けるのは 2 つだ。 1 つ目は、元の支払いの tx(0xc5ce…b92e)と、再送で revert した tx(0x6de9…75c1)が、同じブロック 48136512 に入っていたことだ。 2 つ目は、参照実装(@x402/evm 2.28.0)の挙動だ。verify は eth_call でシミュレートし、失敗したときに authorizationState を読む。 一方 settle は、simulateInSettle の既定が false で、シミュレーションなしに tx を送り、receipt の失敗を invalid_exact_evm_transaction_failed として返す(exact/facilitator/index.mjs の 89 行付近と 286〜310 行)。今回の観測は、この settle の経路と一致する。 verify が通った理由は、仮説として「元の tx が確定する前に、再送の verify が走った」ことが考えられる。同じブロックに入っていた事実とは矛盾しないが、確かめていない。x402.org のファシリテーターが、どの版でどう設定されているかも分かっていない。 実測はすべてエージェントが叩き、累計のファイルを書き換えたのもエージェントだった この記事の実測は、すべて Claude Code のサブエージェント(Sonnet)が、Bash で pnpm buy を実行して取った。私が手で叩いたものはない。エージェントが受け取ったのは、前掲のログと同じ出力である。 エージェントに財布を持たせたとき、手元に残るのは、この出力と買い手の残高だけだ。署名の中身を表示する spy を挟んだのは、そのためである。 実測の途中でもう 1 つ起きたことがある。累計上限の実験の前に、.x402-spend.json は 0.04 まで進んでいた。それまでの署名の分だ。このまま走らせると、1 回目から上限に近づき、「2 回払って 3 回目で止まる」実験にならない。 そこで .x402-spend.json を 0 に書き戻してから実験を走らせた。書き戻しは(2 回目の計測ではこちらの指示で)エージェントが行い、何の抵抗もなく通った。実験の意図に沿った操作で、問題があったわけではない。 ただ、これは実演になっている。累計の上限は、エージェント自身が書き換えられるファイルに置いてあった。上限を守らせたい相手の手の届く場所に、上限の記録を置いたことになる。 この記事のクライアントでは、上限の置き場所はエージェントの手の中だ。人間側、エージェントが触れない場所に置く必要がある。次回の論点になる。 詰まったこと 売り手のディレクトリに、買い手の鍵を置かない apps/paid-api/.env.local は、ルートの .env へのシンボリックリンクだ。.env には BUYER_PRIVATE_KEY が入っている。売り手のディレクトリから、買い手の鍵が見えていた。 vercel CLI がこのファイルをアップロードするかを、私は確信できなかった。調べると、CLI 64.2.0 に同梱のソースでは、既定の無視リストに .env.local と .env.*.local が入っていた。アップロードはされていなかったと見ている。 公式ドキュメント(vercel deploy、2026 年 10 月 15 日に確認)には、既定の無視リストがあるという記述はあるが、中身は載っていない。根拠はドキュメントではなくソースだ。デプロイ先のサーバーに実際に何が上がったかは、確かめていない。 確信が持てなかったので、apps/paid-api/.vercelignore に .env* を足した。Vercel の環境変数に入れたのは PAY_TO_ADDRESS だけで、鍵は置いていない。 教訓は 1 つだ。売り手のディレクトリに、買い手の鍵を置かない。 残高が RPC に反映されるまで遅れる 1 回目の計測の最初の 200 の直後は残高が 19.99 のままだった(公開 RPC の反映遅れのようだ)ので、以降は実行の 8 秒後に読んだ。 Vercel まわりで詰まった 3 つ Production に PAY_TO_ADDRESS が無かった。 第 1 回では、PAY_TO_ADDRESS を Preview にだけ入れていた。Production のデプロイは、accepts[0] に payTo が無い 402 を返していた。Production にも追加した。アドレスは公開情報だ。 dev は型を見ない。 /api/throw の戻り値を Promise<Response> で書いた。dev では動いたが、vercel --prod のビルドは Promise<NextResponse> を要求して、2 回失敗した(TS2345)。NextResponse に直して通った。 公開 URL の保護を外した。 Vercel の Deployment Protection が有効だと、curl が認証ページに当たる。npx vercel project protection disable paid-api --sso で外した(Vercel のドキュメント)。外すと、既存のデプロイが全部公開になる。テストネットの API だから許容したが、他の用途では確認が要る。 次回は MCP サーバーの有料ツールを、Claude から呼ぶ 今回の buy.ts は、コマンドとして人が(あるいはエージェントが)叩くものだった。次回は、これを MCP サーバーの中に入れる。 自作の MCP サーバーに有料のツールを置き、Claude が自分の財布でそれを呼ぶ。上限は、エージェントが触れない側に置きたい。「払ってよいか」を判断する場所が、ツールの呼び出しのどこに来るかが論点になる。 動かしてみる 必要なものは Node 22 以上、pnpm、jq、gitleaks。第 1 回と同じ手順で始める。 git clone suzukitech/agent-payments-lab cd agent-payments-lab git checkout x402-02 git config core.hooksPath .githooks pnpm install pnpm gen-wallets pnpm dev gen-wallets が表示した買い手のアドレスに、Base Sepolia の USDC を入れる(Circle の faucet)。ETH は要らない。秘密鍵は .env に入る。連載専用のテスト用なので、他の用途に流用しないこと。 別のターミナルで、ローカルの API を買う。 pnpm buy localhost 公開 URL に対しても、同じコマンドで払える(テストネット、1 回 $0.01)。 pnpm buy paid-api-flax.vercel.app 上限は引数で変える。既定は 1 回 0.01、累計 0.05 だ。 pnpm buy localhost --max-per-call 0.005 pnpm buy localhost --max-total 0.02 累計は apps/agent-client/.x402-spend.json に溜まる。リセットしたいときはこのファイルを消す。 参考リンク suzukitech/agent-payments-lab(x402-02) x402-foundation/x402(specs/x402-specification-v2.md、specs/transports-v2/http.md、specs/schemes/exact/scheme_exact_evm.md) EIP-3009: Transfer With Authorization EIP-712: Typed structured data hashing and signing Keyrock「Who Pays the Agent?」(2026 年 10 月 15 日に確認) CoinDesk: Crypto rails are becoming the default payment layer for AI agents vercel deploy(CLI のドキュメント) Vercel Authentication Basescan の tx(通常の 200) Basescan の tx(公開 URL への支払い) Basescan の tx(再送の元になった支払い、0xc5ce…) Basescan の tx(1 回目の計測で、curl 再送が通ったもの、0x8bef…) Basescan の tx(2 回目の計測で、curl 再送が通ったもの、0x6d03…) Basescan の tx(再送で revert したもの、0x6de9…)

  8. X402 for messaging. Just imagine the value proposition. Imagine this on @solana for me. Cmon now. @bot x @muse x402#3943

    2 likes · 1 repost · 252 views
  9. What a disclosed x402 SDK flaw looks like on Base, measured On 22 October 2026 the security firm V12 reported that the x402 client SDKs, before version 2.23.0, signed whatever amount a 402 response asked for. The default client had no spending limit, so a hostile API could turn a routine request into a request for the wallet's full balance of a supported token. The fix shipped in the 18 August releases: a $1 cap per payment and recognised dollar stablecoins only, by default. No security advisory was published, and npm audit shows nothing for the vulnerable versions (The Hacker News, 23 Oct 2026). That is the code side. We read the settlement side. The question Every stablecoin transfer into an x402 seller listed in the Bazaar on Base lands in our ledger (definition x402.settle.submitter.v4). So: how often does a settlement arrive far above what the seller is usually paid? The numbers Measured 2026-10-24T08:50Z, for 12 to 23 October 2026, at the 80 sellers with 20 or more settlements in the window (32,605 settlements, $18,950.78 in total): | Rule | Settlements | |---|---:| | At least 10× the seller's median | 1,126 (3.5%) | | At least 100× the seller's median | 65 | | At least 100× and at least $1 | 25, worth $1,928.23, from 13 payers to 7 sellers | The largest cases: | Settlement | Seller's median | Seller's settlements in the window | |---:|---:|---:| | $588.00 | $0.01 | 233 | | $340.00 | $0.002 | 32 | | $302.40 | $0.001 | 27 | | $276.37 | $0.001 | 27 | All four were re-read from Base's public node by transaction receipt; the USDC transfer to the seller carries exactly these amounts. What it is, and what it is not It is the on-chain shape of the flaw: a client that signs the amount it is asked for. It is also the shape of tiered or usage-based pricing, and the chain cannot tell the two apart. Read these as the ceiling of what the overcharge vector could have been on Base in those twelve days, not as a count of overcharges. The payer side points the same way. Over 30 days the 25 cases come from 13 payers; none of them is an ERC-8004-bound agent wallet; ten of the thirteen made only one or two settlements in the whole month. The large cases look like single purchases, not an agent in a loop. What it does establish: payments far above a seller's usual price settle on mainnet in the normal course of business, and a per-payment cap does not see them. A $1 cap lets a tenfold overcharge of a cheap resource through without a trace. The control that would have had something to act on is a caller-side price expectation. If you run an x402 client 1. Upgrade to @x402/fetch / @x402/axios 2.23.0 or later (2.28.0 as of 23 Oct); apps using SIWx also need @x402/extensions 2.23.0+. 2. Set maxAmountPerPayment at the price you expect to pay, not at a round number. 3. Use the onBeforePaymentCreation hook to compare amount, payTo, network and asset in the 402 with the quote you accepted, and refuse when they differ (x402-foundation/x402#3866 has the discussion and fixtures). 4. Never pass spendControls: false in production. Where the series lives We publish the count every day as x402_settle_oversize_7d (and x402_settle_oversize_usd_7d): definition, per-settlement list, free, CC BY 4.0. We posted the figures in x402#3866 so the people fixing the client have mainnet numbers next to their fixtures. This is how we intend to treat every disclosed flaw in an agent-payment rail: write the on-chain shape, measure it two ways, publish the series, keep publishing after the news moves on. Witness, not police; the client decides.

    1 reaction · 1 comment
  10. 🤖 x402: AI agents can make payments now. But is the infrastructure actually secure? Imagine an AI agent that needs data from a paid API to complete a task. Instead of asking a human to create an account, configure an API key, and handle billing, the agent could discover the price, authorize a payment, and retrieve the resource on its own. Sounds useful, right? That's the idea behind x402, an open payment protocol built around HTTP's "402 Payment Required" status code. It enables applications and AI agents to pay for digital resources directly through HTTP requests. But there's an important question we should ask before getting too excited about autonomous payments: Can we trust an AI agent to spend money without human intervention? Let's take a closer look at how x402 works, why stablecoins matter, how much it can transact, and what security research tells us about the risks. 💸 What exactly is x402? The basic idea is pretty straightforward. An application requests a resource from an API. If payment is required, the server responds with "402 Payment Required" and provides the accepted payment options. The client can then select an option, sign a payment authorization, and retry the request. The server verifies the payment and follows the configured settlement flow before releasing the resource. This makes it possible to charge for individual API calls, data queries, model inference, or other digital services without necessarily requiring a traditional subscription or API-key-based billing system. The interesting part is that payment becomes part of the application workflow itself. Instead of integrating a separate billing process into every interaction, developers can use a standardized payment flow over existing web infrastructure. 🪙 Why are stablecoins important here? x402 defines the payment flow, but it doesn't require a single currency or blockchain. Stablecoins such as USDC are particularly relevant because they're designed to maintain a relatively stable value against the US dollar. When supported by the chosen network and implementation, they can be used for programmatic payments with predictable dollar-denominated prices. Think about an agent that needs to: - Retrieve market data from one API. - Pay for additional information from another provider. - Run an inference request using a specialized model. - Combine the results and generate a report. Each service could charge for its own usage, and the agent could pay as it goes. This creates opportunities for new business models based on micropayments rather than subscriptions or prepaid API credits. Of course, stablecoins aren't risk-free. Issuer solvency, liquidity, custody, smart contracts, and blockchain availability still matter. 💰 Is x402 limited to microtransactions? Not inherently. Microtransactions are a use case, not a fixed transaction-size limit imposed by the protocol. The amount an x402 payment can transfer depends on the payment scheme, blockchain, supported asset, available balance, and implementation-specific constraints. For example, an API might charge $0.01 for a data query, while another service could charge $5 for a specialized AI inference request. Both fit the general idea of paying for digital resources through HTTP. The protocol also supports different payment models. The "exact" scheme handles a specified payment amount, while "upto" allows a client to authorize a maximum amount for one request and the server to settle the actual usage up to that ceiling. That second approach is particularly useful for AI services where the final cost depends on the number of tokens generated or the amount of computing consumed. For instance, an agent could authorize up to $5 for an inference request and pay $1.85 if that is the actual usage cost. The implementation must enforce that the final charge never exceeds the authorized maximum. There is an important caveat, though: there is no single maximum transaction amount that applies universally to every x402 implementation. Network-specific rules, token constraints, payment mechanisms, and application policies can all impose limits. Some client SDK configurations also apply their own spending safeguards. The x402 project's default-asset configuration, for example, documents a default maximum of $1 per payment for recognized USD-pegged assets. That is a client-side spending control, not a protocol-wide ceiling; the applicable configuration and version need to be checked. So why do people associate x402 with micropayments? Because its ability to attach payments to individual requests makes small, frequent transactions much more practical as an application design. It doesn't mean larger payments are categorically forbidden. And regardless of transaction size, developers still need spending limits. A protocol that supports a $100 payment doesn't mean an AI agent should automatically be allowed to authorize one. 🔐 How does x402 handle security? This is where things get more interesting. x402 includes security mechanisms such as cryptographic signatures, payment validity windows, and protections against replaying payment authorizations. These mechanisms help establish that a payment authorization is valid and that its signed contents haven't been altered. However, a valid signature doesn't automatically mean a transaction is safe. A secure implementation must also validate the payment amount, recipient, asset, network, and relationship between the payment and the requested resource. It must handle transaction confirmation correctly and prevent the same purchase from being settled or fulfilled multiple times. There's another important distinction: the protocol doesn't automatically impose a spending budget on the AI agent. The agent might be technically capable of making valid payments while still making terrible financial decisions. For example, it could pay an excessive price, repeatedly purchase the same data, or follow malicious payment instructions supplied by an untrusted service. These aren't problems that cryptography alone can solve. ⚠️ Security research raises some important questions In May 2026, researchers published a preprint titled "Five Attacks on x402 Agentic Payment Protocol" (arxiv.org). The paper describes five attacks involving weaknesses in authorization, payment-to-resource binding, replay protection, and web-layer handling. According to the researchers, their attacks were tested in research environments and against live endpoints. The reported outcomes included scenarios where services could be accessed without successful payment and situations where payment occurred but access to the resource was denied. These findings deserve attention, but we need to be precise about what they mean. The paper is a research preprint. Its findings don't establish that every x402 implementation is vulnerable, nor do they prove that every reported issue affects the latest versions of all SDKs and integrations. What they do highlight is a broader engineering challenge: security must cover the entire payment workflow, not just the blockchain transaction. A payment can be cryptographically valid while the surrounding application still behaves incorrectly. And for autonomous agents, that distinction matters a lot. 🛡️ What would a safer architecture look like? I wouldn't give an AI agent unrestricted access to a wallet and simply assume it will make sensible decisions. Instead, I'd separate the model's reasoning from the component responsible for authorizing financial operations. The agent can decide that it needs a service. A separate policy layer should determine whether the proposed payment is allowed. That layer could enforce: - Per-transaction limits: The agent cannot spend more than a predefined amount on a single request. - Cumulative budgets: Total spending is restricted over a given period or task. - Allowlisted assets and recipients: Payments are restricted to approved tokens, networks, and destinations where appropriate. - Payment validation: Amounts and recipients are checked before authorization is signed. - Idempotency and replay protection: Retries don't accidentally produce duplicate charges or deliveries. - Secure key management: The model doesn't receive unrestricted access to private-key material. - Auditing and monitoring: Payments can be inspected, traced, and investigated after execution. The exact controls depend on the payment scheme, network, and application. They shouldn't be assumed to exist automatically just because an implementation uses x402. This is also why I think agentic payments are as much an application-security challenge as they are a payments-infrastructure challenge. 🌐 So, are we ready for truly autonomous payments? x402 is an interesting step toward an internet where software can discover services, negotiate payment requirements, and pay for resources programmatically. Stablecoins make this particularly compelling by enabling digital payments that can be denominated in familiar units of value. And the protocol isn't restricted to micropayments. It can support different payment amounts and usage-based pricing models, provided the chosen implementation and network support the transaction. But enabling an agent to spend money is only one part of the problem. We also need reliable authorization, spending policies, transaction verification, secure key management, and correct handling of failures across the entire system. And we need to test these controls against adversarial scenarios, rather than assuming that a successful transaction means everything worked as intended. For me, the central question isn't whether AI agents can make payments. They can. The real challenge is building systems that can constrain, verify, and audit what an agent is allowed to spend — before something goes wrong. I'd be interested to hear how other developers are approaching this problem. Would you let an autonomous agent spend from a wallet today? What safeguards would you require before putting such a system into production? --- 📚 References 1. x402 Protocol — Official repository and specification x402-foundation/x402 2. x402 V2 — Protocol specification github.com/x402-foundation/x402/blob/main/specs/x… 3. x402 — Exact payment scheme github.com/x402-foundation/x402/blob/main/specs/s… 4. x402 — Usage-based "upto" payment scheme github.com/x402-foundation/x402/blob/main/specs/s… 5. x402 — Default assets and client-side spending controls github.com/x402-foundation/x402/blob/main/DEFAULT… 6. Solana Documentation — x402 Payments solana.com 7. Research paper — Five Attacks on x402 Agentic Payment Protocol arxiv.org Note: The research paper is a preprint. Its findings should be interpreted in the context of the tested implementations and environments, rather than as proof that all x402 deployments are vulnerable. Spending limits may also differ between SDK versions and configurations.

    1 reaction

Achievements

Awards earned by the repositories x402-foundation owns. Select an award to embed its badge.

No awards yet

Repositories earn awards by reaching the top three in a completed trending day or week.

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.