<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: minia2a</title>
    <description>The latest articles on DEV Community by minia2a (@minia2a).</description>
    <link>https://dev.to/minia2a</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4067568%2Fb2a82151-f089-4653-8084-15d5577a1da2.png</url>
      <title>DEV Community: minia2a</title>
      <link>https://dev.to/minia2a</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/minia2a"/>
    <language>en</language>
    <item>
      <title>"The x402 facilitator: what actually sits between an agent and the chain when it pays a cent"</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Thu, 27 Aug 2026 16:59:17 +0000</pubDate>
      <link>https://dev.to/minia2a/the-x402-facilitator-what-actually-sits-between-an-agent-and-the-chain-when-it-pays-a-cent-4731</link>
      <guid>https://dev.to/minia2a/the-x402-facilitator-what-actually-sits-between-an-agent-and-the-chain-when-it-pays-a-cent-4731</guid>
      <description>&lt;h1&gt;
  
  
  The x402 facilitator: what actually sits between an agent and the chain when it pays a cent
&lt;/h1&gt;

&lt;p&gt;Most writing about agent payments stops at the happy path: an AI agent hits a paywalled endpoint, gets a &lt;code&gt;402 Payment Required&lt;/code&gt;, signs a transaction, retries with proof of payment, and gets a response. That is the part of x402 everyone talks about.&lt;/p&gt;

&lt;p&gt;This article is about the part nobody diagrams: the &lt;strong&gt;facilitator&lt;/strong&gt; — the component that actually accepts the payment and settles it with the person running the API. If you are building a paid agent API, the facilitator is the thing you are really choosing. Everything else is plumbing around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The three roles in an x402 exchange
&lt;/h2&gt;

&lt;p&gt;The spec splits a paid call into three parties, and the split matters more than the protocol version:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Client&lt;/strong&gt; — the agent. It wants a resource and has a wallet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resource server&lt;/strong&gt; — the API. It has the resource and wants to be paid before releasing it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Facilitator&lt;/strong&gt; — the entity that takes the money on the resource server's behalf.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When a resource server returns &lt;code&gt;402&lt;/code&gt;, the challenge says &lt;em&gt;who&lt;/em&gt; to pay (&lt;code&gt;payTo&lt;/code&gt;) and &lt;em&gt;how much&lt;/em&gt;. In a direct setup the &lt;code&gt;payTo&lt;/code&gt; is the resource server's own address. In a facilitated setup, &lt;code&gt;payTo&lt;/code&gt; is the facilitator's address, and the facilitator later forwards the settlement to the resource server.&lt;/p&gt;

&lt;p&gt;That indirection is the entire point. The facilitator absorbs everything the resource server does not want to run itself: wallet custody, chain connectivity, gas management, and the reconciliation of "who paid how much for what."&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the facilitator exists at all
&lt;/h2&gt;

&lt;p&gt;A resource server &lt;em&gt;could&lt;/em&gt; just put its own address in &lt;code&gt;payTo&lt;/code&gt; and watch the chain. Almost nobody does, for four reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Gas is a tax on cents.&lt;/strong&gt; Settling a $0.01 call on a chain with a $0.10 fee is a 10x loss. The facilitator exists to batch, hold off-chain, or absorb gas so per-call economics survive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One address per chain is painful.&lt;/strong&gt; An API that wants to accept USDC on five networks now runs five key pairs and five balance books. A facilitator collapses that into one settlement surface.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconciliation is the hard part.&lt;/strong&gt; Payments arrive as unstructured chain transactions. Someone has to map "0.003 USDC from 0x9f... at block 12M" onto "agent X bought tool Y for $0.003." That mapping is a database, not a protocol feature.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trust is easier to outsource.&lt;/strong&gt; A buyer that does not know your API will still pay a facilitator it recognizes. The facilitator is a reputational bridge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The settlement chain, end to end
&lt;/h2&gt;

&lt;p&gt;Here is the chain a cent actually travels, from left to right:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;agent wallet → facilitator (payTo) → [batch/ledger] → facilitator payout wallet
                                                          ↓
                                              resource server's wallet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;402&lt;/code&gt; challenge is the &lt;em&gt;front&lt;/em&gt; of this chain. The back half — facilitator internal ledger, payout batching, on-chain settlement — is not standardized. That is the interesting part: &lt;strong&gt;x402 standardizes the challenge, not the settlement.&lt;/strong&gt; Two facilitators can be 100% spec-compatible and settle completely differently.&lt;/p&gt;

&lt;h2&gt;
  
  
  The design axes that actually distinguish facilitators
&lt;/h2&gt;

&lt;p&gt;If you are evaluating (or building) a facilitator, these four axes matter more than the brand name.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Gasless vs. gas-bearing
&lt;/h3&gt;

&lt;p&gt;A gasless facilitator pays the chain fees itself and marks it up (or subsidizes it). A gas-bearing facilitator passes gas through to the buyer. Gasless is a better developer experience and a worse margin; the choice is really "who eats the fee on a $0.01 call."&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Pass-through vs. credit/reseller
&lt;/h3&gt;

&lt;p&gt;A pass-through facilitator moves money from buyer to seller 1:1 minus a fee. A &lt;strong&gt;reseller facilitator&lt;/strong&gt; does not move the buyer's money at all — it meters its own credits to the agent and pays the resource server separately. The agent never holds a direct relationship with the resource server. Reseller models are attractive because they abstract the chain away entirely, but they concentrate trust in the facilitator.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Single-rail vs. multi-rail
&lt;/h3&gt;

&lt;p&gt;A single-rail facilitator settles on one chain (usually one stablecoin on one L2). A multi-rail facilitator accepts payment on several and settles on whichever the resource server prefers. Multi-rail is more capital-efficient for buyers but multiplies the reconciliation problem.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Hosted vs. self-hosted
&lt;/h3&gt;

&lt;p&gt;A hosted facilitator is a service you point &lt;code&gt;payTo&lt;/code&gt; at. A self-hosted facilitator is software you run next to your API. Self-hosted keeps custody and margin, at the cost of running a wallet and a reconciliation pipeline you were probably trying to avoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for the protocol's future
&lt;/h2&gt;

&lt;p&gt;The existence of a second HTTP-402 standard — MPP, from Stripe, Tempo, and Visa, deliberately backward-compatible with x402 — is a signal, not a fight. When a payment rail is being built as &lt;em&gt;infrastructure&lt;/em&gt; by card networks, the rails are becoming a commodity. The value is migrating to the layer above the rail: who holds the relationship with the buyer, who does the reconciliation, who vouches for the seller.&lt;/p&gt;

&lt;p&gt;That layer is the facilitator. The next few years of agent payments will be decided less by which protocol wins and more by how the facilitator role shakes out — whether it consolidates into a few big settlement networks or fragments into thousands of self-hosted gateways. Watch that, not the version numbers.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is a technical explainer, not product commentary. The roles and flows described are part of the public x402 specification and its ecosystem; organizations are named only where they are the authors of a public specification.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>x402</category>
      <category>m2m</category>
      <category>payments</category>
      <category>web3</category>
    </item>
    <item>
      <title>MCP 2026-07-28 Went Stateless — and Still Has No Way to Charge for a Call</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Thu, 27 Aug 2026 09:06:55 +0000</pubDate>
      <link>https://dev.to/minia2a/mcp-2026-07-28-went-stateless-and-still-has-no-way-to-charge-for-a-call-3l2g</link>
      <guid>https://dev.to/minia2a/mcp-2026-07-28-went-stateless-and-still-has-no-way-to-charge-for-a-call-3l2g</guid>
      <description>&lt;h1&gt;
  
  
  MCP 2026-07-28 Went Stateless — and Still Has No Way to Charge for a Call
&lt;/h1&gt;

&lt;p&gt;The Model Context Protocol's July 28 revision is the biggest architectural change since launch. It is not an incremental bump — it's a rewrite of the protocol's core assumption. And yet the one thing server authors keep asking for — a way to get paid — is still, deliberately, not there.&lt;/p&gt;

&lt;p&gt;This post is two things: an accurate map of what &lt;em&gt;actually&lt;/em&gt; changed (a lot of the summaries floating around get it wrong), and a concrete pattern for the payment gap, using HTTP 402.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually shipped: the protocol went stateless
&lt;/h2&gt;

&lt;p&gt;The headline is &lt;strong&gt;statelessness&lt;/strong&gt;. Prior revisions assumed a long-lived session: client calls &lt;code&gt;initialize&lt;/code&gt;, server returns a session ID, both sides keep per-session state. The 2026-07-28 revision removes that assumption.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;th&gt;What it means&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;initialize&lt;/code&gt; handshake removed&lt;/td&gt;
&lt;td&gt;No session ID. Each request carries its own version + capabilities in &lt;code&gt;_meta.io.modelcontextprotocol/{protocolVersion, clientInfo, clientCapabilities}&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;New &lt;code&gt;server/discover&lt;/code&gt; RPC&lt;/td&gt;
&lt;td&gt;Clients learn supported versions and capabilities up front; SDKs fall back to legacy &lt;code&gt;initialize&lt;/code&gt; for old servers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stateless-only Streamable HTTP&lt;/td&gt;
&lt;td&gt;The &lt;code&gt;streamable&lt;/code&gt; transport accepts 2026-07-28 only in stateless mode; stateful sessions negotiate down to 2025-11-25&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Removed methods&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;ping&lt;/code&gt;, &lt;code&gt;logging/setLevel&lt;/code&gt;, &lt;code&gt;resources/subscribe&lt;/code&gt;, &lt;code&gt;resources/unsubscribe&lt;/code&gt;, and SSE resumability (&lt;code&gt;Last-Event-ID&lt;/code&gt;, standalone GET) are gone — they reject with &lt;code&gt;MethodNotFound&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MRTR (SEP-2322)&lt;/td&gt;
&lt;td&gt;Multi-round-trip requests replace holding an SSE stream open. A server returns &lt;code&gt;InputRequiredResult&lt;/code&gt; (&lt;code&gt;resultType: "inputRequired"&lt;/code&gt;) with an opaque &lt;code&gt;requestState&lt;/code&gt;; the client re-issues the request with &lt;code&gt;inputResponses&lt;/code&gt; + that same &lt;code&gt;requestState&lt;/code&gt;. Any replica can pick up the retry — that's the point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Header routing (SEP-2243)&lt;/td&gt;
&lt;td&gt;Every Streamable HTTP POST carries &lt;code&gt;Mcp-Method&lt;/code&gt; (mirroring the JSON-RPC method), plus &lt;code&gt;Mcp-Name&lt;/code&gt; for &lt;code&gt;tools/call&lt;/code&gt;, &lt;code&gt;resources/read&lt;/code&gt;, &lt;code&gt;prompts/get&lt;/code&gt;. Intermediaries can route without parsing bodies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cacheable lists (SEP-2549)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;tools/list&lt;/code&gt;, &lt;code&gt;prompts/list&lt;/code&gt;, &lt;code&gt;resources/list&lt;/code&gt; carry &lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt; freshness hints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real HTTP errors&lt;/td&gt;
&lt;td&gt;Transport failures return actual status codes instead of HTTP 200 with an in-body JSON-RPC error: unknown method → 404, unsupported version → 400 (&lt;code&gt;-32022&lt;/code&gt;), missing capability → &lt;code&gt;-32021&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Equally important is what got &lt;strong&gt;deprecated&lt;/strong&gt;: &lt;code&gt;roots&lt;/code&gt;, &lt;code&gt;sampling&lt;/code&gt;, and &lt;code&gt;logging&lt;/code&gt; (SEP-2577), plus the legacy HTTP+SSE transport and Dynamic Client Registration (replaced by Client ID Metadata Documents). A lot of the "MCP added OAuth DCR and roots!" summaries have it exactly backwards — those were the old model, now on the way out.&lt;/p&gt;

&lt;p&gt;The through-line: the protocol is being rebuilt so that &lt;strong&gt;any request can be routed to any replica, with no shared session state&lt;/strong&gt;. That's a property you want if you're running an MCP gateway, a load balancer, or a fleet of servers behind one endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  What did &lt;em&gt;not&lt;/em&gt; change: there's still no payment layer
&lt;/h2&gt;

&lt;p&gt;Search the spec for a way to charge for a &lt;code&gt;tools/call&lt;/code&gt; and you won't find one. This is a deliberate design decision, not an omission. MCP solves &lt;strong&gt;discovery&lt;/strong&gt; (what tools exist) and &lt;strong&gt;capability&lt;/strong&gt; (what they do). Commerce — who owes whom — is a different protocol's job, and the maintainers have been consistent that it's out of scope.&lt;/p&gt;

&lt;p&gt;The reasoning is sound. A tool-integration protocol should not bake in a pricing model, a settlement rail, or a currency. Those things rot fast. But the decision leaves a concrete problem for anyone running a non-free MCP server: &lt;strong&gt;when an agent calls your tool, how do you get paid?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The ecosystem's answer is converging on &lt;strong&gt;HTTP 402 Payment Required&lt;/strong&gt; — the status code that's been reserved since 1997 and is finally being used for its intended purpose. The standard that operationalizes it is &lt;strong&gt;x402&lt;/strong&gt;, which is now under the Linux Foundation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How HTTP 402 gates an MCP server
&lt;/h2&gt;

&lt;p&gt;The mechanism is refreshingly small. When a request arrives without proof of payment, you return &lt;code&gt;402&lt;/code&gt; with payment instructions in the &lt;code&gt;WWW-Authenticate&lt;/code&gt; header. The caller pays, retries with proof, and you verify. One request cycle, no account system.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/mcp&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;span class="na"&gt;Mcp-Method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tools/call&lt;/span&gt;
&lt;span class="na"&gt;Mcp-Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;lookup_contract&lt;/span&gt;

&lt;span class="err"&gt;HTTP/&lt;/span&gt;&lt;span class="mf"&gt;1.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;402&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Payment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Required&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;WWW-Authenticate:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Payment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;version=&lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;asset=&lt;/span&gt;&lt;span class="s2"&gt;"USDC"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;chain=&lt;/span&gt;&lt;span class="s2"&gt;"base"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;receiver=&lt;/span&gt;&lt;span class="s2"&gt;"0x…"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;price=&lt;/span&gt;&lt;span class="s2"&gt;"0.01"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;Content-Type:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;application/json&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"payment required"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0.01 USDC"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A working Express middleware for the gate — placed before your &lt;code&gt;tools/call&lt;/code&gt; handler:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/mcp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isToolCall&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mcp-method&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isToolCall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;proof&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-payment-proof&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;402&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WWW-Authenticate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Payment version="1.0", asset="USDC", chain="base", &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;receiver="&amp;lt;YOUR-RECEIVER&amp;gt;", price="0.01"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payment required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.01 USDC&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Verify the proof against the facilitator that settled it.&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;verifyPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;proof&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;402&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payment invalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details worth getting right in production:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;Mcp-Method: tools/call&lt;/code&gt; is now a routing header&lt;/strong&gt; (SEP-2243). You can gate &lt;em&gt;only&lt;/em&gt; paid tools by matching on it, rather than intercepting every POST and inspecting the JSON-RPC body. Free tools (&lt;code&gt;Mcp-Method: tools/list&lt;/code&gt;, etc.) pass straight through.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verification is delegated to a facilitator.&lt;/strong&gt; You don't need to parse the chain or manage USDC custody yourself. The payment proof is a receipt a facilitator issued; you POST it back to the facilitator's verify endpoint and get a yes/no. Your server stays a stateless replica — which is exactly the property 2026-07-28 just worked to give you.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The stateless rewrite is a gift to paid endpoints
&lt;/h2&gt;

&lt;p&gt;This is the part that connects the two halves. Payment gating and statelessness &lt;em&gt;reinforce&lt;/em&gt; each other:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;code&gt;402&lt;/code&gt; + retry pattern is naturally idempotent. If your server is a stateless replica, a client can hit &lt;em&gt;any&lt;/em&gt; replica with the same paid request and get the same result. No session affinity to fight.&lt;/li&gt;
&lt;li&gt;MRTR gives you &lt;code&gt;requestState&lt;/code&gt; tokens, so a multi-step paid interaction (request → pay → confirm → result) can span replicas without sticky sessions.&lt;/li&gt;
&lt;li&gt;Real HTTP status codes mean a &lt;code&gt;402&lt;/code&gt; is a &lt;code&gt;402&lt;/code&gt;, not a JSON-RPC error wrapped in HTTP 200. Agents and gateways can branch on it cheaply.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're building a non-free MCP server right now, the stateless model removes most of the infrastructure reasons you couldn't charge before.&lt;/p&gt;

&lt;h2&gt;
  
  
  The other paths (and why they're complementary, not competitors)
&lt;/h2&gt;

&lt;p&gt;HTTP 402 is not the only answer, and it's worth knowing the map:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;MPP (Machine Payments Protocol)&lt;/strong&gt; — a second standard (Stripe + Tempo + Visa) that also uses HTTP 402 and adds session/subscription semantics on top. Backward-compatible with x402 at the 402-challenge level.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MCP Billing Spec v1&lt;/strong&gt; — a community draft (&lt;code&gt;noui.bot&lt;/code&gt;) that layers billing metadata over MCP's &lt;code&gt;_meta&lt;/code&gt; namespace, closer to the tool protocol itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS AgentCore&lt;/strong&gt; — wraps MCP servers behind a gateway that adds auth and metering; payment is handled by the platform, not the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are in the MCP core spec, and none of them should be. The clean split — MCP for tools, 402 for payment, a facilitator for settlement — is the shape that's actually stabilizing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom line
&lt;/h2&gt;

&lt;p&gt;MCP 2026-07-28 is a protocol-level bet that agents will talk to &lt;strong&gt;stateless fleets of tools, not stateful single servers&lt;/strong&gt;. It removed the session assumption, standardized routing and multi-round-trip interaction, and got rid of the things that tied a server to a single machine.&lt;/p&gt;

&lt;p&gt;It did &lt;em&gt;not&lt;/em&gt; add payments — and that's correct. The payment layer lives one status code below the tool protocol. If you run an MCP server that should earn money, the path is: return &lt;code&gt;402&lt;/code&gt; with payment instructions, verify the receipt through a facilitator, and let the stateless architecture you're now building on do the rest.&lt;/p&gt;

</description>
      <category>mcp</category>
      <category>x402</category>
      <category>payments</category>
      <category>ai</category>
    </item>
    <item>
      <title>The Most-Sampled Endpoints Have Zero Paid Calls</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Tue, 25 Aug 2026 16:14:07 +0000</pubDate>
      <link>https://dev.to/minia2a/the-most-sampled-endpoints-have-zero-paid-calls-mo</link>
      <guid>https://dev.to/minia2a/the-most-sampled-endpoints-have-zero-paid-calls-mo</guid>
      <description>&lt;p&gt;Trial counts are the wrong metric. Every API marketplace reports them because they look like demand, but at the endpoint level, the number of free samples and the number of paid calls barely correlate.&lt;/p&gt;

&lt;p&gt;I pulled the per-endpoint numbers from a live pay-per-call marketplace for AI agents and found the two most-sampled endpoints — over 4,700 trials each — have been paid for &lt;strong&gt;zero times&lt;/strong&gt;. Meanwhile the endpoints that actually earn money are mostly the boring ones nobody leads a pitch with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trial volume ≠ demand
&lt;/h2&gt;

&lt;p&gt;Sort every endpoint by free trials consumed, and the top of the list looks like a healthy business:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Trials&lt;/th&gt;
&lt;th&gt;Paid calls&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Gas&lt;/td&gt;
&lt;td&gt;crypto&lt;/td&gt;
&lt;td&gt;4,715&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Captcha Solve&lt;/td&gt;
&lt;td&gt;specialized&lt;/td&gt;
&lt;td&gt;4,626&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recall&lt;/td&gt;
&lt;td&gt;ai&lt;/td&gt;
&lt;td&gt;3,867&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;utility&lt;/td&gt;
&lt;td&gt;1,652&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Find&lt;/td&gt;
&lt;td&gt;ai&lt;/td&gt;
&lt;td&gt;1,629&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polymarket&lt;/td&gt;
&lt;td&gt;finance&lt;/td&gt;
&lt;td&gt;1,240&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The top two rows are pure samples: thousands of free calls, not a single paid one. The trial counter inflates; the ledger doesn't move. Reading "4,700 trials" as "4,700 units of demand" is reading a number that has nothing to do with money.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually gets paid
&lt;/h2&gt;

&lt;p&gt;Sort by real paid calls instead, and the picture inverts:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Category&lt;/th&gt;
&lt;th&gt;Paid calls&lt;/th&gt;
&lt;th&gt;Trials&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;utility&lt;/td&gt;
&lt;td&gt;40&lt;/td&gt;
&lt;td&gt;1,652&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Recall&lt;/td&gt;
&lt;td&gt;ai&lt;/td&gt;
&lt;td&gt;36&lt;/td&gt;
&lt;td&gt;3,867&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Token Security&lt;/td&gt;
&lt;td&gt;security&lt;/td&gt;
&lt;td&gt;14&lt;/td&gt;
&lt;td&gt;186&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Domain Intel&lt;/td&gt;
&lt;td&gt;web&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wallet&lt;/td&gt;
&lt;td&gt;identity&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;63&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Crypto Price&lt;/td&gt;
&lt;td&gt;crypto&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Smart Contract Audit&lt;/td&gt;
&lt;td&gt;contract-audit&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;0 (no trial)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The paid cluster is &lt;strong&gt;utility + security/audit + web/domain intel&lt;/strong&gt;. And the last row is the interesting one: the audit endpoint offers &lt;em&gt;no free trial at all&lt;/em&gt;, yet it's in the top tier of earners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sampling vs. buying are different behaviors
&lt;/h2&gt;

&lt;p&gt;The split makes sense once you see them as two different behaviors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sampling&lt;/strong&gt; is free and reflexive. An agent will trial gas prices or a captcha solver because it can, not because it needs to pay for them — both are trivial to self-serve or find free elsewhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Buying&lt;/strong&gt; only happens when the endpoint does a job the agent can't do for itself: verify a token, audit a contract, resolve domain intelligence.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So free samples pile up on the trivially-replaceable endpoints, and money goes to the hard-to-replace ones. Trial volume is &lt;em&gt;inversely&lt;/em&gt; correlated with paid conversion — not because trials are bad, but because what gets sampled freely and what is worth paying for are almost disjoint sets.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The honest metric is paid calls per endpoint, not trials.&lt;/strong&gt; A design that hands out unlimited free sampling produces a flattering trial counter and an empty ledger.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What this means for trial design
&lt;/h2&gt;

&lt;p&gt;If the goal is real usage (not demo theater), the trial allowance should be tight enough that the trial counter means something: a small shared allowance gets a caller to the moment of "do I pay for this?" without letting the demo counter masquerade as revenue.&lt;/p&gt;

&lt;p&gt;The endpoints that convert are the ones where the free sample ends and a real job begins. Everything else is just traffic.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Data from the live service catalog of &lt;a href="https://minia2a.uk" rel="noopener noreferrer"&gt;minia2a.uk&lt;/a&gt;, pulled August 25, 2026. "Paid calls" counts real pay-per-call usage, not the free trial allowance.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>ai</category>
      <category>payments</category>
      <category>programming</category>
    </item>
    <item>
      <title>Agents are starting to pay to be checked before they act</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Sun, 23 Aug 2026 23:03:09 +0000</pubDate>
      <link>https://dev.to/minia2a/agents-are-starting-to-pay-to-be-checked-before-they-act-2aa9</link>
      <guid>https://dev.to/minia2a/agents-are-starting-to-pay-to-be-checked-before-they-act-2aa9</guid>
      <description>&lt;h2&gt;
  
  
  Agents are starting to pay to be checked before they act
&lt;/h2&gt;

&lt;p&gt;The first generation of agent spending was "pay to fetch" — an agent pays a few cents to pull a price, scrape a page, or run a query. That's a solved problem now.&lt;/p&gt;

&lt;p&gt;The second generation is starting to show up, and it's a different primitive entirely: &lt;strong&gt;pay a third party to validate a high-stakes action before you commit to it.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I track a public index of pay-per-call machine endpoints. On August 23 I pulled the full thing — 15,297 listings across 1,613 hosts — and compared it to a baseline two days earlier. The churn was the usual long tail of ephemeral tunnels and single-endpoint demos. But among the genuinely new operators, three independent hosts — nobody coordinating, all in the same window — converged on the same product: &lt;strong&gt;pre-flight validation.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Three flavors of "check before you commit"
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Outbound-payment preflight&lt;/strong&gt; — check a payout destination and amount for changed recipients, duplicates, and policy breaches before authorizing. One check per payment, stateless; a cent beats a wrong transfer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQL preflight&lt;/strong&gt; — check a query against a Postgres schema before execution: destructive writes, unsafe changes. Agents are increasingly the ones writing the SQL; a guardrail is worth more than the rollback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unsigned-transaction preflight&lt;/strong&gt; — simulate an unsigned transaction (eth_call + gas estimate) before signing and broadcasting. Catches a revert before gas is spent and before state changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I probed the cluster directly rather than trusting the listings: the payment-gated endpoints return live 402 payment challenges to a POST, meaning these are working products charging today, not listing stubs. That's the difference between "someone thought of this" and "someone is charging for it."&lt;/p&gt;

&lt;h3&gt;
  
  
  The industrial edge: bounded validation jobs
&lt;/h3&gt;

&lt;p&gt;The most striking new entrant isn't crypto at all. One host published sixty endpoints under a buyer-jobs schema, each a &lt;em&gt;bounded&lt;/em&gt; validation task: validate a robot trajectory's timing, check closed-loop stability, tune a controller within supplied limits, verify collision constraints, compare state estimators. The same host lists quantum jobs — provider-readiness checks, execution-plan selection, circuit compilation.&lt;/p&gt;

&lt;p&gt;Every description uses the same word: &lt;strong&gt;bounded&lt;/strong&gt;. The caller supplies the limits; the service checks the input against them. It's validation as a commodity — deterministic, cheap, and only needed at the moment a decision hangs on it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why validation fits pay-per-call
&lt;/h3&gt;

&lt;p&gt;Validation has exactly the properties a micropayment rail rewards:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Small&lt;/strong&gt; — a preflight check is a few hundred bytes in, a yes/no or a bounded report out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateless&lt;/strong&gt; — each check is independent; no subscription, no retained state.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High downside&lt;/strong&gt; — the thing being checked (a payment, a signed transaction, a deploy) is expensive to get wrong, so a cent's worth of checking is a rational purchase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Not self-certifiable&lt;/strong&gt; — an autonomous agent can verify data, but it can't verify its own judgment about a high-stakes action. Validation is the one thing it genuinely has to outsource.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The honest caveat
&lt;/h3&gt;

&lt;p&gt;This is an &lt;em&gt;emerging&lt;/em&gt; category, not an established market. The validation listings are new, and their 30-day usage sits near the floor of one call — the listing-time probe, not repeat demand. The demand head — the endpoints agents actually pay for today — is still oracle data, fresh social data, search, and enrichment.&lt;/p&gt;

&lt;p&gt;But a category doesn't need to be big to be real. Three uncoordinated operators arriving at the same primitive in the same week — one of them already live and payment-gated — is how new layers form. The first act was "pay to fetch." The second act is shaping up to be &lt;strong&gt;"pay to verify."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're building an agent that moves money, writes state, or signs transactions, watch this space — the pre-flight check you're hand-rolling today may already be a commodity someone is charging a cent for.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Cross-posted from &lt;a href="https://minia2a.uk/blog/x402-preflight-validation-category-august-2026" rel="noopener noreferrer"&gt;minia2a.uk&lt;/a&gt;. Data from a full pull of a public pay-per-call discovery index on 2026-08-23.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Agent-Payments Stack Just Went Full-Stack</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Sun, 23 Aug 2026 11:37:25 +0000</pubDate>
      <link>https://dev.to/minia2a/the-agent-payments-stack-just-went-full-stack-2c50</link>
      <guid>https://dev.to/minia2a/the-agent-payments-stack-just-went-full-stack-2c50</guid>
      <description>&lt;p&gt;For the last few months, the agent-payments market looked like a layer cake where every layer had a different owner. One team did settlement. Another did wallets. Another did gateway. Another did discovery. Nobody owned more than one slice.&lt;/p&gt;

&lt;p&gt;That changed this week. A single operator surfaced in the x402 discovery stream that ships &lt;strong&gt;four layers at once&lt;/strong&gt; — an agent wallet, card issuing, a self-serve payment gateway, and settlement — plus a trading surface on top. The stack is consolidating, and the consolidation tells you something important about where this market is headed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The stack, before this week
&lt;/h2&gt;

&lt;p&gt;Strip the jargon away and agent payments decompose into six layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;th&gt;Recent shape&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Protocol&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How a price is attached to a request&lt;/td&gt;
&lt;td&gt;x402 (HTTP 402 + payment metadata), MPP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Settlement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How the money actually moves&lt;/td&gt;
&lt;td&gt;USDC on Base/other chains; gas-free nanopayment primitives in testnet&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wallet&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Where an agent holds funds&lt;/td&gt;
&lt;td&gt;Agent accounts with spending controls&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Credit / issuing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fiat rails an agent can spend through&lt;/td&gt;
&lt;td&gt;Card issuing on digital-asset collateral&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Gateway / facilitator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Turns an existing API into a paid endpoint&lt;/td&gt;
&lt;td&gt;No-code wrappers, OpenAPI import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Discovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;How an agent finds an endpoint to pay&lt;/td&gt;
&lt;td&gt;Marketplaces and catalogs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Until now these were mostly &lt;em&gt;separate companies&lt;/em&gt;. The protocol work lived at foundations. Settlement lived at stablecoin infra. Wallets were one thing, gateways another, discovery a third. Each layer was a point-tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  What surfaced this week
&lt;/h2&gt;

&lt;p&gt;This week's x402 discovery sweep — a daily crawl of a public x402 resource directory — surfaced an operator that collapses four of those layers into one product:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A wallet for agents&lt;/strong&gt; — an account an agent can use to pay, earn, and invest across cards, bank accounts, and crypto, with programmatic spending controls (daily budget, per-transaction limit, an allow-list of approved domains).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A card.&lt;/strong&gt; This is the new primitive. The operator advertises a &lt;em&gt;Visa-network credit card issued by a Visa principal member, collateralized by digital assets&lt;/em&gt; — accepted anywhere Visa is accepted, and separate from the crypto wallet. It's the first time I've seen an agent-facing card paired with a wallet and a gateway in one product.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;A self-serve gateway&lt;/strong&gt; — paste your API's base URL and auth, set per-endpoint pricing (flat, dynamic, or session-based), and publish. Sellers get a subdomain per protocol (&lt;code&gt;your-service.x402.vendor.com&lt;/code&gt; and &lt;code&gt;your-service.mpp.vendor.com&lt;/code&gt;). OpenAPI bulk-import, session billing with escrow, and an MCP surface so an agent can create endpoints itself.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual-rail settlement&lt;/strong&gt; — x402 and MPP behind one gateway, so a seller collects USDC either way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And the tell that this is real rather than a landing page: one of its gateway-hosted endpoints — a third-party screenshot API wrapped behind the vendor's gateway — already showed up in the public discovery directory. The no-code gateway is onboarding supply, and that supply is flowing into public discovery.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The layer cake is collapsing. Full-stack operators will absorb the single-purpose point-tools — and the layer that stays scarce is discovery.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Why the card matters more than it looks
&lt;/h2&gt;

&lt;p&gt;The wallet and the gateway are interesting. The &lt;strong&gt;card&lt;/strong&gt; is the signal.&lt;/p&gt;

&lt;p&gt;An agent wallet that holds USDC can only spend where x402 (or a handful of other crypto rails) is accepted. A Visa-network card can spend &lt;em&gt;anywhere Visa is accepted&lt;/em&gt;, backed by digital-asset collateral that sits on the operator's ledger. That's a fiat on-ramp for agents — it turns "an agent can pay for x402 endpoints" into "an agent can pay for anything," with the crypto rails doing settlement underneath.&lt;/p&gt;

&lt;p&gt;For the demand side of the agent economy, that's the missing piece. The honest bottleneck in this market has never been the rails — it's been &lt;em&gt;demand generation&lt;/em&gt;: getting real agents to actually pay for a call. A card makes an agent a first-class payer in the fiat economy, not just the crypto one.&lt;/p&gt;

&lt;h2&gt;
  
  
  What consolidation means for builders
&lt;/h2&gt;

&lt;p&gt;If full-stack operators absorb wallets, cards, gateways, and settlement, then the layer a single-purpose team can still win is &lt;strong&gt;discovery and trust&lt;/strong&gt; — the market layer where an agent figures out which of thousands of pay-per-call endpoints is real, what it costs, and whether it will actually answer.&lt;/p&gt;

&lt;p&gt;When the rails, the wallets, the cards, and the gateways all consolidate into full-stack platforms, the scarce resource isn't "who can move a micropayment." It's &lt;strong&gt;"who can tell an agent which endpoint to trust with that micropayment."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Method note: the operator described here is unnamed deliberately — this is a pattern analysis, not a review of any single company. Observations come from the public x402 discovery directory and the operator's own public site.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>x402 Did ~14M Agent Transfers in 30 Days. The Rails Are Solved — Discovery Isn’t.</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Fri, 21 Aug 2026 15:27:39 +0000</pubDate>
      <link>https://dev.to/minia2a/x402-did-14m-agent-transfers-in-30-days-the-rails-are-solved-discovery-isnt-44lg</link>
      <guid>https://dev.to/minia2a/x402-did-14m-agent-transfers-in-30-days-the-rails-are-solved-discovery-isnt-44lg</guid>
      <description>&lt;p&gt;For a year the open question about machine-to-machine payments wasn't &lt;em&gt;how&lt;/em&gt; — the x402 standard (HTTP 402 + USDC) had an answer — but &lt;em&gt;whether anyone would actually do it&lt;/em&gt;. Every skeptical take boiled down to the same line: "agents don't have wallets, and they don't pay for APIs."&lt;/p&gt;

&lt;p&gt;That question just got a number. &lt;strong&gt;Token Terminal reports ~14 million AI agent transfers on x402 rails in the trailing 30 days&lt;/strong&gt;, published August 19, 2026: ~7.3M on Base, ~5.6M on Polygon, with USDC settling nearly all of it.&lt;/p&gt;

&lt;p&gt;Fourteen million is no longer an early-adopter anecdote. It's volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the volume actually is
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rail&lt;/th&gt;
&lt;th&gt;30-day transfers&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Base&lt;/td&gt;
&lt;td&gt;~7.3M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Polygon&lt;/td&gt;
&lt;td&gt;~5.6M&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Combined&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~12.9M of ~14M&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Both are first-party rails of the same protocol steward, and the transfers run through its own agent ecosystems. This is not 14 million agents wandering the open web, each discovering a new pay-per-call API and settling on-chain. It's a concentrated garden where the rails, the clients, and the endpoints were built together. That's the right way to bootstrap a standard — but it tells you what the 14M proves and what it doesn't.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the 14M proves: the rails are done
&lt;/h2&gt;

&lt;p&gt;The rails debate is over. Machines will pay machines, at scale, in USDC, over HTTP 402. The settlement asset is settled (USDC, not a dozen tokens), and the tooling is real — this month also brought AWS Bedrock AgentCore payments to GA (x402 + USDC with spending limits) and enterprise USDC collection for agent payments. When the hyperscaler and the protocol steward both ship agent-payment rails in the same week, "will agents pay" stops being a research question.&lt;/p&gt;

&lt;p&gt;The binding constraint moved. It is now &lt;strong&gt;discovery&lt;/strong&gt;: how does an agent that already knows how to pay x402 find the &lt;em&gt;other&lt;/em&gt; things worth paying for — the long tail outside the first-party garden?&lt;/p&gt;

&lt;h2&gt;
  
  
  What the 14M doesn't prove: the open long tail has demand
&lt;/h2&gt;

&lt;p&gt;I can report this from the inside, and it's uncomfortable: the open long tail is still near zero. Our own open x402 catalog — 1,662 pay-per-call services — has recorded &lt;strong&gt;90 real on-chain settlements totaling $11.52 USDC&lt;/strong&gt;. That's the honest number, and it is five orders of magnitude away from the 14M flowing through the first-party rails.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The gap isn't proof that open marketplaces fail. It's proof that the 14M agents were never given a reason — or a path — to buy anything outside the garden.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two honest reasons:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. The traffic is rails-bound, not discovery-bound.&lt;/strong&gt; An agent built on the steward's SDK pays the steward's endpoints. Nothing in that flow surfaces a cheaper CAPTCHA solver or a niche data feed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. The open long tail is invisible to the machines that would pay it.&lt;/strong&gt; Most third-party x402 services are a repo and a README. An agent can't pay for a service it can't find, and it can't find a service that never published itself in a form agents read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovery is the whole game now
&lt;/h2&gt;

&lt;p&gt;If the rails are commoditizing, the durable position isn't "another payment rail" — it's the index. Three properties matter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Open, not first-party.&lt;/strong&gt; Any publisher can list a real endpoint. The long tail is the point.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trial-first.&lt;/strong&gt; An agent should verify a service answers correctly before it pays. Pay-per-call, but verify-first.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Machine-readable.&lt;/strong&gt; A &lt;code&gt;.well-known/x402&lt;/code&gt; record, a JSON directory, an MCP server. Discovery only counts if a machine can do it without a human clicking around.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The 14M didn't change what we build. It changed what's worth arguing about. Nobody needs convincing that agent payments are a thing — the 14M agents already exist and already pay. The work now is making sure that when one of them wants something the first-party garden doesn't sell, there's an open index it can ask.&lt;/p&gt;

&lt;p&gt;The rails are solved. Discovery is the next bottleneck, and the next bottleneck is the opportunity.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>webdev</category>
      <category>payments</category>
    </item>
    <item>
      <title>Your Agent's Trial Call Needs a Signature — and the Service ID Isn't What You Think</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Wed, 19 Aug 2026 04:29:39 +0000</pubDate>
      <link>https://dev.to/minia2a/your-agents-trial-call-needs-a-signature-and-the-service-id-isnt-what-you-think-46a</link>
      <guid>https://dev.to/minia2a/your-agents-trial-call-needs-a-signature-and-the-service-id-isnt-what-you-think-46a</guid>
      <description>&lt;p&gt;An agent registers a self-custody wallet, appends &lt;code&gt;?wallet=0x…&lt;/code&gt; to an endpoint the way the quickstart shows — and gets &lt;code&gt;HTTP 402&lt;/code&gt;. Nothing is down. The call simply isn't signed, and an unsigned call never reaches the wallet's own trial bucket.&lt;/p&gt;

&lt;p&gt;Everything below was measured against a live x402 gateway on August 19, 2026. The pass/fail marks are real responses, not documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two buckets, not one
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Anonymous&lt;/strong&gt; — 15 calls keyed to your egress IP, shared across the whole catalog.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registered wallet&lt;/strong&gt; — a further 15 calls keyed to the wallet itself, reachable &lt;em&gt;only&lt;/em&gt; by signing each call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They're genuinely independent. My measurements came from a host whose anonymous bucket was already at &lt;code&gt;0/15&lt;/code&gt;: unsigned calls returned 402, and signed calls from the same host in the same second returned 200. If your agents run behind shared cloud egress — Lambda, CI runners, a Workers deploy where thousands of tenants share an IP — that's the difference between "free tier exhausted before I started" and "my wallet carries its own allowance wherever it runs."&lt;/p&gt;

&lt;h2&gt;
  
  
  The message
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minia2a trial:&amp;lt;wallet&amp;gt;:&amp;lt;serviceId&amp;gt;:&amp;lt;unixSeconds&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sign with EIP-191 (&lt;code&gt;personal_sign&lt;/code&gt;), send &lt;code&gt;X-Wallet-Signature&lt;/code&gt; + &lt;code&gt;X-Trial-Timestamp&lt;/code&gt;, put the wallet in the query string. Timestamp is unix seconds, ±5 minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The detail that costs an afternoon
&lt;/h2&gt;

&lt;p&gt;You're standing at the URL &lt;code&gt;https://minia2a.uk/x402/time&lt;/code&gt;. The obvious reading of &lt;code&gt;serviceId&lt;/code&gt; is &lt;code&gt;time&lt;/code&gt;. It isn't — it's the catalog &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;x402-time&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Four candidates, same wallet, same endpoint, same minute:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Signed as&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;x402-time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;200&lt;/strong&gt; — &lt;code&gt;x-trial-mode: wallet&lt;/code&gt;, &lt;code&gt;x-trial-remaining: 14&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;402&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/x402/time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;402&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;https://minia2a.uk/x402/time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;402&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Confirmed on a second endpoint: &lt;code&gt;gas&lt;/code&gt; → 402, &lt;code&gt;x402-gas&lt;/code&gt; → 200.&lt;/p&gt;

&lt;p&gt;Here's why this is worse than an ordinary gotcha. &lt;strong&gt;A wrong service ID and a forged signature produce byte-identical responses&lt;/strong&gt; — both a 402 with &lt;code&gt;trial.mode:"none"&lt;/code&gt;. An agent debugging this has no signal telling it whether its crypto is wrong, its clock is wrong, its registration failed, or it merely used the wrong noun. So it goes and rewrites the signing code, which was fine all along.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general lesson, for anyone designing a payment challenge
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;A 402 body that names a variable — "sign &lt;code&gt;wallet:service:ts&lt;/code&gt;" — is not machine-readable. The client has to guess what &lt;code&gt;service&lt;/code&gt; expands to, and every wrong guess looks exactly like an auth failure. Emit the literal string, or name the field it comes from.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The cost of that ambiguity lands entirely on the caller, which in the agent economy means it lands on software that cannot file a bug report. Humans work around ambiguous errors by asking someone. Agents retry, exhaust a budget, and give up — and you never hear about it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python that works
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eth_account&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;eth_account.messages&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;encode_defunct&lt;/span&gt;

&lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Account&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PRIVATE_KEY&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x402-time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;time&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;span class="n"&gt;sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sign_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;encode_defunct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;minia2a trial:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;signature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hex&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://minia2a.uk/x402/time?wallet=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;acct&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                 &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-Wallet-Signature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;X-Trial-Timestamp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-trial-mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;x-trial-remaining&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Don't infer which bucket paid — read the header
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;x-trial-mode: wallet&lt;/code&gt; — signature accepted.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;x-trial-mode: ip&lt;/code&gt; — you're on the anonymous bucket; something in the signed message was wrong and the call quietly fell back.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That &lt;code&gt;ip&lt;/code&gt; case is the quiet one: &lt;strong&gt;a 200 doesn't prove your signing works&lt;/strong&gt;, it may just prove your IP still had calls left. Test from an exhausted IP, or watch the header. Those are the only two honest checks.&lt;/p&gt;




&lt;p&gt;Full write-up with curl/CLI/MCP recipes: &lt;a href="https://minia2a.uk/blog/x402-signed-trial-calls-august-2026" rel="noopener noreferrer"&gt;minia2a.uk/blog/x402-signed-trial-calls-august-2026&lt;/a&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Every Number On Our Site Was Typed Once</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Wed, 19 Aug 2026 00:57:55 +0000</pubDate>
      <link>https://dev.to/minia2a/every-number-on-our-site-was-typed-once-2oe8</link>
      <guid>https://dev.to/minia2a/every-number-on-our-site-was-typed-once-2oe8</guid>
      <description>&lt;p&gt;Our homepage said this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your agents discover, pay, and consume APIs autonomously in USDC on Base.
300+ services across crypto, web, AI, and data.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The catalog held 1,645. That sentence is the one line on the page whose entire job is to convey scale, and it was understating by more than five times.&lt;/p&gt;

&lt;p&gt;The same bug ran the other way too. An internal dashboard page advertised &lt;em&gt;1,700 services&lt;/em&gt; — a number the catalog has never actually reached. And the worst instance was in a file no human reads: the &lt;code&gt;.well-known&lt;/code&gt; record that LLM crawlers ingest described us as &lt;em&gt;"272 agent-callable APIs"&lt;/em&gt;, with a metadata block frozen three weeks earlier. When someone asks a model how big that directory is, 272 is the number it has to work with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three directions, one cause
&lt;/h2&gt;

&lt;p&gt;Under-claiming, over-claiming, and telling a crawler something six times too small look like three different mistakes. They are one: a number was typed into a file, the thing it described kept moving, and nothing ever reconnected them.&lt;/p&gt;

&lt;p&gt;That's worth naming precisely, because it isn't a content problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A count in your copy is a cached API response with no expiry and no owner.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every marketing page, every &lt;code&gt;.well-known&lt;/code&gt; record, every &lt;code&gt;llms.txt&lt;/code&gt; is a client of your own stats endpoint that somebody hand-resolved once, months ago.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The test that finds these:&lt;/strong&gt; grep your site for digits followed by the words you use for your own inventory — &lt;em&gt;services&lt;/em&gt;, &lt;em&gt;endpoints&lt;/em&gt;, &lt;em&gt;APIs&lt;/em&gt;, &lt;em&gt;users&lt;/em&gt; — and diff every hit against the live value. We found 17 files. One was current.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fixing the numbers is the wrong fix
&lt;/h2&gt;

&lt;p&gt;We'd already fixed the numbers once. A hand-patching pass the day before had walked straight past two &lt;code&gt;272&lt;/code&gt; strings in the very file that feeds LLM catalogs — because hand-patching a list of files is exactly the kind of job that silently drops an item.&lt;/p&gt;

&lt;p&gt;So we replaced it in two shapes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pages resolve at render time.&lt;/strong&gt; A component already existed that rewrites any &lt;code&gt;&amp;lt;span data-stat="services"&amp;gt;&lt;/code&gt; from &lt;code&gt;/api/stats&lt;/code&gt; on load. Eleven pages used it; the pages with wrong numbers didn't. The counts became spans, the missing pages got the script tag, and the value written into the HTML is the current live one — so a crawler or a JS-less reader still sees today's figure.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Static records get rewritten daily, floored downward.&lt;/strong&gt; JSON records can't run JavaScript, so a cron rewrites them from live stats. One rule matters more than the rest:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Prose counts floor, never round up. 1,645 publishes as "1,600+", never "1,700".&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A floored claim is one you can always defend. A rounded-up one is a small lie that grows every time your catalog dips.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the alarm, not just the fix
&lt;/h2&gt;

&lt;p&gt;Self-correcting scripts have a specific failure mode: they die quietly and everything looks fine. So the verification suite got a check comparing published claims against live — a prose count must land in &lt;code&gt;(live − 100, live]&lt;/code&gt;. Below that, the record stopped tracking. Above it, we're over-claiming. Both fail.&lt;/p&gt;

&lt;p&gt;Then the part that's easy to skip. We put the old number back and watched it fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="go"&gt;FAIL  published counts: /.well-known/ai-catalog.json: claims 272, live 1645
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…ran the refresher, watched it heal, re-ran the suite green. &lt;strong&gt;A guard you've only ever seen pass is a guard you haven't tested.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The near-miss worth writing down
&lt;/h2&gt;

&lt;p&gt;One page compares marketplaces. A single table row holds our count, one competitor's &lt;em&gt;5,000 registered agents&lt;/em&gt;, and another's &lt;em&gt;845 paid APIs&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The general rule — "a number followed by &lt;em&gt;registered agents&lt;/em&gt; is our wallet count" — is correct on nine pages and catastrophically wrong on the tenth. The dry run said exactly what it planned to do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;L124: 5,000 -&amp;gt; &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;data-stat=&lt;/span&gt;&lt;span class="s"&gt;"wallets"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;775&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That edit would have republished a competitor's figure as ours. Not a stale number — a fabricated one, about somebody else's business. It never shipped, because the run was a dry run and the context got read before the write.&lt;/p&gt;

&lt;p&gt;The fix: comparison pages get a literal-scoped rule that touches only our own value and leaves every other number alone. The lesson is narrower than "be careful":&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An automation that rewrites claims has to know which claims are yours to rewrite. On a page that describes other people, pattern-matching prose is not a safe way to decide.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  If you run an agent-facing service
&lt;/h2&gt;

&lt;p&gt;Agents don't sanity-check your numbers the way a human skimming a landing page does. They read &lt;code&gt;llms.txt&lt;/code&gt;, &lt;code&gt;.well-known&lt;/code&gt; records, and OpenAPI specs literally and act on what they find.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One source of truth.&lt;/strong&gt; Every published count resolves from the same endpoint your dashboard reads. If a number in your copy can't name its source, it doesn't have one.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Floor, don't round.&lt;/strong&gt; Publishing less than you have costs nothing you can measure. Publishing more costs the thing that's hard to rebuild.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plant the old wrong value and watch the check fail.&lt;/strong&gt; Otherwise you have a dashboard, not a guard.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Full write-up with the exact regex traps and guardrails: &lt;a href="https://minia2a.uk/blog/stale-number-problem-august-2026" rel="noopener noreferrer"&gt;Every Number On Our Site Was Typed Once&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>devops</category>
      <category>ai</category>
    </item>
    <item>
      <title>What Our Own Discovery Records Were Telling Agents</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Wed, 19 Aug 2026 00:11:46 +0000</pubDate>
      <link>https://dev.to/minia2a/what-our-own-discovery-records-were-telling-agents-o0g</link>
      <guid>https://dev.to/minia2a/what-our-own-discovery-records-were-telling-agents-o0g</guid>
      <description>&lt;p&gt;A discovery record is an API contract that nothing validates. Your tests exercise your API; nothing exercises the JSON file that tells strangers what your API costs.&lt;/p&gt;

&lt;p&gt;We run an x402 resource server, and we finally diffed every machine-readable record we publish against the live &lt;code&gt;402&lt;/code&gt; responses those records describe. A third of our published prices were 100×–500× below what the gateway actually charges. The published payout address was one we no longer settle to. Our OpenAPI spec pointed buyers at a URL that served the same data for free.&lt;/p&gt;

&lt;p&gt;None of this showed up as an outage. Every record returned HTTP 200, well-formed JSON, on time. That's the whole problem with the discovery layer: &lt;strong&gt;a record that lies is indistinguishable from a record that works&lt;/strong&gt;, right up until a buyer acts on it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The crawler that chased single characters
&lt;/h2&gt;

&lt;p&gt;The audit started with a log shape that made no sense. In one day, one IP requested &lt;code&gt;/n&lt;/code&gt; 116 times, &lt;code&gt;/s&lt;/code&gt; 87 times, &lt;code&gt;/i&lt;/code&gt; 87, &lt;code&gt;/e&lt;/code&gt; 87, then a long tail of single-character paths at 58 and 29 hits. 1,189 requests, all 404, all one character long.&lt;/p&gt;

&lt;p&gt;The counts are the tell — they're all multiples of 29: 4×29, 3×29, 2×29, 1×29. That's a character-frequency histogram: some string, iterated 29 times. Solving for a string with four &lt;code&gt;n&lt;/code&gt;, three each of &lt;code&gt;s&lt;/code&gt;/&lt;code&gt;i&lt;/code&gt;/&lt;code&gt;e&lt;/code&gt;, two each of &lt;code&gt;t&lt;/code&gt;/&lt;code&gt;o&lt;/code&gt;/&lt;code&gt;l&lt;/code&gt;/&lt;code&gt;k&lt;/code&gt;/&lt;code&gt;a&lt;/code&gt;/&lt;code&gt;w&lt;/code&gt;/&lt;code&gt;2&lt;/code&gt;/&lt;code&gt;-&lt;/code&gt;, one each of &lt;code&gt;x&lt;/code&gt;/&lt;code&gt;v&lt;/code&gt;/&lt;code&gt;u&lt;/code&gt;/&lt;code&gt;r&lt;/code&gt;/&lt;code&gt;p&lt;/code&gt;/&lt;code&gt;m&lt;/code&gt;/&lt;code&gt;j&lt;/code&gt;/&lt;code&gt;h&lt;/code&gt;/&lt;code&gt;c&lt;/code&gt;/&lt;code&gt;4&lt;/code&gt;/&lt;code&gt;0&lt;/code&gt; gives exactly one answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;https://minia&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="err"&gt;a.uk/.well-known/x&lt;/span&gt;&lt;span class="mi"&gt;402&lt;/span&gt;&lt;span class="err"&gt;-service.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;code&gt;/&lt;/code&gt; and &lt;code&gt;.&lt;/code&gt; are absent from the histogram because those requests normalize or redirect instead of 404 — itself a confirmation.)&lt;/p&gt;

&lt;p&gt;A client was iterating that URL as if it were a list. And it had a good reason to. We published the field name &lt;code&gt;endpoints&lt;/code&gt; in two sibling records:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Record&lt;/th&gt;
&lt;th&gt;
&lt;code&gt;endpoints&lt;/code&gt; is…&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/.well-known/x402-service.json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;an array of 82 endpoint objects&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/.well-known/x402&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;a bare URL string&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Any consumer that learned the field from the first record and then read the second gets a string where it expected a collection. In Python or JavaScript, iterating a string doesn't throw — it quietly yields characters. So the crawler fetched &lt;code&gt;/h&lt;/code&gt;, &lt;code&gt;/t&lt;/code&gt;, &lt;code&gt;/t&lt;/code&gt;, &lt;code&gt;/p&lt;/code&gt;, &lt;code&gt;/s&lt;/code&gt;, and never once reached our catalog.&lt;/p&gt;

&lt;p&gt;We had been reading that as crawler noise. It was our schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  A third of the prices were fiction
&lt;/h2&gt;

&lt;p&gt;Regenerating one record from the other meant actually reading the catalog, which surfaced something worse: &lt;strong&gt;33 of 82 entries had a published price that disagreed with the live 402.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Our gas-price endpoint was published at &lt;code&gt;0.005&lt;/code&gt; USDC. Its actual challenge:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"accepts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"500000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="err"&gt;-decimal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;USDC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.005&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"asset"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"0x8335...2913"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"payTo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s2"&gt;"0xf16F0882..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scheme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"exact"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A hundred times the advertised number. Across the catalog the ratios clustered at 100× (20 entries), 500× (6), 50× (2), plus one each at 300×, 10×, 5×.&lt;/p&gt;

&lt;p&gt;Under-pricing sounds like the harmless direction to be wrong in. It isn't. An agent that budgets from your catalog and then meets a paywall demanding 100× more doesn't negotiate — it fails the call or silently overpays. Either way the number you published wasn't a price, it was a guess someone made once and nobody re-checked.&lt;/p&gt;

&lt;p&gt;The same audit found the catalog's &lt;code&gt;payment.address&lt;/code&gt; naming a wallet the gateway no longer settles to. All 82 live 402s named the current address; the published record named a different one. &lt;strong&gt;USDC sent to the address we advertised would not have been credited.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The spec that routed buyers around our own paywall
&lt;/h2&gt;

&lt;p&gt;Most of our services are gateway-proxied, so the published path is ours and the 402 happens at our edge. A handful are seller-hosted: the seller runs the API on their own infrastructure and registers it with us.&lt;/p&gt;

&lt;p&gt;For those, our generator published &lt;em&gt;the seller's upstream path&lt;/em&gt;, with an operation-level &lt;code&gt;servers&lt;/code&gt; override pointing at the seller's host. Legal OpenAPI. Wrong twice over:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;It 404s for most tooling.&lt;/strong&gt; Operation-level &lt;code&gt;servers&lt;/code&gt; overrides are widely ignored; plenty of clients build the URL from the root server and land on a path our domain never served. 16 such 404s in one day from a single indexer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It bypasses the paywall entirely.&lt;/strong&gt; We fetched one of those upstreams directly: 200, complete dataset, no 402 challenge at all. Our spec printed a price next to a URL that serves the data free, never touches our gateway, and never settles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We were advertising our own bypass. Every one of those services answers a proper 402 at the gateway's proxy route, so that's what we publish now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four records described an auth scheme we don't implement
&lt;/h2&gt;

&lt;p&gt;Four records described agent registration as Ed25519 keypair signing. The gateway verifies EIP-191 &lt;code&gt;personal_sign&lt;/code&gt; over an exact message string. One of those records is aimed specifically at LLM and catalog ingestion, and its example query read &lt;em&gt;"register my agent using my Ed25519 key"&lt;/em&gt; — feeding a nonexistent integration path to the systems most likely to repeat it verbatim.&lt;/p&gt;

&lt;p&gt;Another named a registration endpoint that only answers GET. It returns a pointer to the real endpoint, which is sensible — but the record called the pointer the endpoint, so anything that POSTed where we said to POST got a 404.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why none of it was caught
&lt;/h2&gt;

&lt;p&gt;Every defect has the same shape: &lt;strong&gt;a claim about the system, stored outside the system, that nothing re-derives.&lt;/strong&gt; Prices were copied into JSON when they were true. The payout address was correct when written. The Ed25519 description matched a design that changed. The type mismatch was two people reasonably naming two different things &lt;code&gt;endpoints&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Static files don't rot on their own — they rot because the thing they describe moves. So the fix isn't "be more careful when editing JSON":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Derive from the 402, not from a cache.&lt;/strong&gt; Price and payout address now come from the actual challenge response, because that's the number the buyer will be charged — not from an internal field that merely ought to agree with it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One source, two records.&lt;/strong&gt; The catalog is regenerated first; the summary record is rebuilt from it. Two files can't disagree about a type if only one is authored.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Probe over loopback.&lt;/strong&gt; An earlier version of this audit probed from outside, rate-limited itself, and read its own &lt;code&gt;429&lt;/code&gt;s as "endpoint healthy" — hiding 71 genuinely dead links behind the throttle. Your own throttle is not a verdict about someone else's uptime.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refuse to publish suspicious deltas.&lt;/strong&gt; The corrector aborts if too many entries fail to resolve. A mass drop is far more likely to be an outage on your side than every seller delisting at once.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Test that your test can fail
&lt;/h3&gt;

&lt;p&gt;This runs daily now and fails loudly on drift. But a check you've only watched pass proves nothing — a regex that matches nothing also reports zero mismatches. So we planted the old wrong price back into the input and confirmed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;handbook prices: x402-gas says 1c, charges 50c   →  FAIL
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then reverted. Two minutes, and it's the difference between a guard and a decoration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publishing a correction doesn't un-publish the old one
&lt;/h2&gt;

&lt;p&gt;One last thing, because it changes what the fix is worth. A separate client has been calling five endpoint IDs that no longer exist, ~720 times a day, for a week — while re-fetching our now-corrected spec hundreds of times a day. The dead IDs are gone from everything we publish. It's still calling them.&lt;/p&gt;

&lt;p&gt;Downstream consumers cache, merge, and hand-copy your records into their configs. Fixing the record fixes the &lt;em&gt;next&lt;/em&gt; reader, not the current ones. Which is the real argument for validating discovery records continuously rather than carefully: every day a wrong record is live, some fraction of its readers commit that error to a config that outlives your fix.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Measured against a live x402 gateway on August 18–19, 2026. Request counts come from the gateway's own log; prices and payout addresses were read from live 402 challenge responses. The seller-hosted upstream that serves without a paywall is deliberately unnamed.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>The Error Message an Agent Can't Act On</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Tue, 18 Aug 2026 21:54:05 +0000</pubDate>
      <link>https://dev.to/minia2a/the-error-message-an-agent-cant-act-on-3o0</link>
      <guid>https://dev.to/minia2a/the-error-message-an-agent-cant-act-on-3o0</guid>
      <description>&lt;p&gt;Our programmatic registration endpoint returns two different HTTP 400s. One of them includes a working &lt;code&gt;curl&lt;/code&gt; example, so a caller that hits it can repair itself. The other says verification failed without ever naming the thing to verify against, so a caller that hits it cannot.&lt;/p&gt;

&lt;p&gt;Over seven days that endpoint took 232 calls and returned success four times.&lt;/p&gt;

&lt;p&gt;The defect was not a missing field in our documentation — we checked, and the documented payload is complete. The defect was an error message with no recovery path in it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we measured
&lt;/h2&gt;

&lt;p&gt;Yesterday we found that every documented path for &lt;em&gt;publishing&lt;/em&gt; a service to our marketplace was broken. That prompted the obvious follow-up about the other side of the market: can a machine that reads only our docs &lt;em&gt;register&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;From the gateway log, August 12 10:31 through August 18 21:45 UTC, &lt;code&gt;POST /api/v1/register-simple&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4 successes out of 232 calls&lt;/strong&gt; — 171 × 400, 24 × 429, 24 × 404.&lt;/p&gt;

&lt;p&gt;Two honest deductions before that number gets quoted anywhere. &lt;strong&gt;41 of those failures were mine&lt;/strong&gt;, from earlier testing against the same endpoint. Another &lt;strong&gt;103 came from a single external indexer&lt;/strong&gt; repeatedly trying to register itself. So this is not 228 lost customers and I won't present it as one.&lt;/p&gt;

&lt;p&gt;It also shouldn't be confused with our registered-wallet count, which is 775. Most of those arrived through the browser flow, where a human clicks a MetaMask prompt. The 4-of-232 figure describes one specific path: the one an autonomous agent walks, with no human present.&lt;/p&gt;

&lt;h2&gt;
  
  
  The asymmetry
&lt;/h2&gt;

&lt;p&gt;We sent seven payload variants and recorded what came back. Usefully, the endpoint validates the signature &lt;em&gt;before&lt;/em&gt; it checks the per-IP limit — so a deliberately invalid signature can probe the contract with no possibility of creating a real account.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What we sent&lt;/th&gt;
&lt;th&gt;What came back&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Empty body / name only / no signature&lt;/td&gt;
&lt;td&gt;400 &lt;code&gt;name, wallet and signature required&lt;/code&gt; — &lt;strong&gt;plus a complete, copy-pasteable curl example&lt;/strong&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Signature over the wrong message, or garbage&lt;/td&gt;
&lt;td&gt;400 &lt;code&gt;signature verification failed — prove you own this wallet by signing the message&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Correct, fully valid payload&lt;/td&gt;
&lt;td&gt;429 &lt;code&gt;one free registration per IP&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the first two rows again. Both are 400s from the same endpoint, and they are not the same kind of object at all.&lt;/p&gt;

&lt;p&gt;The first &lt;strong&gt;contains its own fix&lt;/strong&gt;. A caller that receives it has, right there in the body, the exact shape of the request it should have sent. It can retry correctly without consulting anything.&lt;/p&gt;

&lt;p&gt;The second is a dead end. It says the signature failed and instructs the caller to sign &lt;em&gt;the message&lt;/em&gt; — but never says which message. The answer is the literal string &lt;code&gt;minia2a register: &amp;lt;wallet&amp;gt;&lt;/code&gt;, and that string appears nowhere in the error. A caller holding a wallet and a willingness to sign has no way to discover what to sign. It can retry forever and never converge.&lt;/p&gt;

&lt;p&gt;That's what makes it a machine-specific bug. A human who hits that error opens the docs, finds the signing message, and moves on — thirty seconds lost. An autonomous agent has no such move. The error body &lt;em&gt;is&lt;/em&gt; its documentation, and this one contains nothing it can act on.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The test that generalizes:&lt;/strong&gt; for any error your service returns to a machine, ask whether a caller that receives &lt;em&gt;only that response&lt;/em&gt; can repair its next request. If it can't, the error is a defect — even when the status code is correct, the message is accurate, and the field really is invalid.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The second trap: advice that's right everywhere except where it matters
&lt;/h2&gt;

&lt;p&gt;The other finding was in our own documentation, and it was worse, because it actively instructed agents to fail.&lt;/p&gt;

&lt;p&gt;Our machine-readable docs listed status codes, including:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;429 — rate limited. Back off; do not retry in a tight loop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Correct for every route we serve except one. On registration, a 429 means &lt;code&gt;one free registration per IP&lt;/code&gt;, and that condition is &lt;strong&gt;permanent for that IP&lt;/strong&gt;. It is not a retry-after. An agent following our advice is backing off and retrying a request that will never succeed, for as long as it stays running.&lt;/p&gt;

&lt;p&gt;Agents on shared cloud egress hit this constantly, and it isn't their fault: Lambda, Cloudflare Workers, Railway, and CI runners share exit addresses, so the free grant for that address is routinely already claimed by someone else entirely.&lt;/p&gt;

&lt;p&gt;This gets sharper on September 1, when anonymous trials end and registration becomes the only way in. A misleading 429 today is friction. After that date it's the front door.&lt;/p&gt;

&lt;h2&gt;
  
  
  We verified the recovery before documenting it
&lt;/h2&gt;

&lt;p&gt;The honest advice for an agent that gets a 429 on registration is to stop trying to register — because &lt;strong&gt;registration was never required to use the marketplace&lt;/strong&gt;. It buys the free credit grant. That's all it buys. Paying works without it.&lt;/p&gt;

&lt;p&gt;Rather than assert that, we tested it — generate a wallet that has never touched the platform, call a paid endpoint with it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ # freshly generated, never registered
$ curl "https://minia2a.uk/x402/time?wallet=0x8837...7026&amp;amp;probe=1"
HTTP/2 402
{"accepts":[{"scheme":"exact","network":"eip155:8453",
  "asset":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "payTo":"0xf16F...4ECA","amount":"100000"}, ...]}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A payable challenge, two settlement rails, real &lt;code&gt;payTo&lt;/code&gt; addresses. The unregistered wallet is a first-class customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The 429 semantics are documented&lt;/strong&gt; across our three machine-readable surfaces, as a permanent per-IP condition with the payment path as the stated recovery — replacing the generic backoff advice.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The fix was applied to the generator, not the output.&lt;/strong&gt; One of those files is rebuilt hourly from live state; editing the published copy would have looked correct for up to fifty-nine minutes and then quietly reverted. Worth checking, if you automate your own docs, which of your files are artifacts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The claim is now a daily test.&lt;/strong&gt; We already had a regression check asking whether a machine could publish using only the docs. It now also asserts that an unregistered wallet still receives a challenge carrying a real &lt;code&gt;payTo&lt;/code&gt;. We tell agents they can skip registration and pay directly; if that ever stops being true, our documentation starts lying, and we'd rather hear it from a failing check than from an agent stuck in a loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What we did &lt;em&gt;not&lt;/em&gt; change is the error message itself. Making the signature failure name its expected message — the way the missing-field error already names its curl example — is a gateway change, outside what we alter unilaterally. It's filed. Until it ships, the docs carry the string: &lt;code&gt;minia2a register: &amp;lt;your-wallet&amp;gt;&lt;/code&gt;, EIP-191 personal_sign.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this doesn't explain
&lt;/h2&gt;

&lt;p&gt;It would be tidy to claim this accounts for our conversion gap. It doesn't. We've issued 388,219 free credits and seen 910 spent. Fixing a front door doesn't create demand behind it, and an agent that registers successfully still has to find something worth paying for. The registration path being broken is a real defect worth fixing on its own terms; it is not the explanation for everything downstream, and we've been wrong before by reaching for single causes.&lt;/p&gt;

&lt;p&gt;The narrower claim: two sides of this market were failing for the same underlying reason, discovered a day apart. Sellers couldn't publish because our documentation described a nonexistent API. Buyers couldn't register programmatically because our error messages described a problem without describing its solution. Both are the same category of bug — &lt;strong&gt;information a human routes around and a machine cannot&lt;/strong&gt; — and both were invisible in our metrics, because a 400 and a 429 are exactly what a healthy service returns to bad requests.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>We Documented a Marketplace Nobody Could Join</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Tue, 18 Aug 2026 21:10:59 +0000</pubDate>
      <link>https://dev.to/minia2a/we-documented-a-marketplace-nobody-could-join-54jb</link>
      <guid>https://dev.to/minia2a/we-documented-a-marketplace-nobody-could-join-54jb</guid>
      <description>&lt;p&gt;A developer filed an issue on one of our repos titled &lt;em&gt;"Publisher docs and CLI disagree with live seller API."&lt;/em&gt; They had tried to list an API on our x402 marketplace, followed the published instructions, and got HTTP 400.&lt;/p&gt;

&lt;p&gt;Our first instinct was that they had the wrong route. They claimed the seller endpoint was &lt;code&gt;POST /api/register&lt;/code&gt; with header-based signature auth, which did not match what we believed our own API to be.&lt;/p&gt;

&lt;p&gt;So we tested it against the live gateway instead of arguing from memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/register
  {"name":"...","endpoint":"https://...","priceCents":5,"wallet":"0x..."}
  X-Wallet-Signature: 0x...
  X-Signature-Ts: 1755...

→ {"error":"name, wallet and signature required"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the &lt;em&gt;buyer&lt;/em&gt; registration error. The endpoint ignored &lt;code&gt;endpoint&lt;/code&gt; and &lt;code&gt;priceCents&lt;/code&gt; entirely. We sent the identical request with the two signature headers removed and got a byte-for-byte identical response — proof the handler never reads those headers at all.&lt;/p&gt;

&lt;p&gt;The reporter's conclusion about which route works was wrong. But their complaint was exactly right, and here is why they believed it: &lt;strong&gt;that route and that header scheme are what our own canonical agent guide told them to use.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Four surfaces, four different failures
&lt;/h2&gt;

&lt;p&gt;Once we knew the canonical guide was wrong, we checked every document that describes publishing. Each was broken, and no two were broken the same way.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Document&lt;/th&gt;
&lt;th&gt;What was wrong&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;AGENTS.md&lt;/code&gt; (canonical, linked everywhere)&lt;/td&gt;
&lt;td&gt;Wrong route (a buyer alias), wrong field name (&lt;code&gt;priceCents&lt;/code&gt; vs &lt;code&gt;price_cents&lt;/code&gt;), two required fields missing, plus a documented header-auth scheme that is no longer honoured&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Correct route, example omitted a required field → 400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;agent-cookbook.html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Correct route, same missing field → 400&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mcp-x402.html&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Missing &lt;code&gt;endpoint&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;signature&lt;/code&gt; (both required), wrong field name, invalid category value — four errors in one call&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There was no working documented path. If you read our documentation and tried to sell an API on our marketplace, you could not do it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The error message made it worse
&lt;/h2&gt;

&lt;p&gt;The field everyone was missing is &lt;code&gt;description&lt;/code&gt;, which must be at least 20 characters. Here is what the API returns for an empty request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;POST /api/v1/publish-service  {}
→ {"error":"name, endpoint, wallet and signature required"}
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;description&lt;/code&gt; is not in that list. It is enforced but not announced. A developer doing the sensible thing — reading the error and adding exactly the fields it names — still gets a 400, with a &lt;em&gt;new&lt;/em&gt; error that finally mentions the real requirement.&lt;/p&gt;

&lt;p&gt;This is the part I find most instructive. A wrong example is one problem. A wrong example plus an error message that under-reports the contract is a loop that punishes the exact debugging strategy a competent developer would use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this matters more for agents than for humans
&lt;/h2&gt;

&lt;p&gt;A human who hits a 400 has options. They read the error, try variations, search for someone with the same problem, check the HTML on another page, or email support. Humans route around bad documentation. It costs them time, and some fraction succeed anyway.&lt;/p&gt;

&lt;p&gt;An agent does not do this. It reads &lt;code&gt;AGENTS.md&lt;/code&gt; or &lt;code&gt;llms.txt&lt;/code&gt;, constructs the call exactly as specified, gets a 400, and stops. If it retries, it retries the same wrong shape.&lt;/p&gt;

&lt;p&gt;For an autonomous client, &lt;strong&gt;the documentation is the interface.&lt;/strong&gt; A wrong &lt;code&gt;llms.txt&lt;/code&gt; is not a docs bug — it is an outage that returns 200.&lt;/p&gt;

&lt;p&gt;This is worth sitting with if you are building anything agent-facing. The ecosystem is investing heavily in machine-readable discovery: &lt;code&gt;llms.txt&lt;/code&gt;, agent cards, &lt;code&gt;.well-known&lt;/code&gt; manifests, OpenAPI specs. All of that infrastructure assumes the content is true. We had all of those files. Several were confidently describing an API that would reject you.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the numbers looked like
&lt;/h2&gt;

&lt;p&gt;Our catalog has 1,644 active services. &lt;strong&gt;Twelve&lt;/strong&gt; are hosted outside our own infrastructure. The rest are ours.&lt;/p&gt;

&lt;p&gt;The buyer side — whose documentation was correct throughout — has 775 registered wallets and has served 21,155 free trial calls.&lt;/p&gt;

&lt;p&gt;I am not going to claim documentation is the sole cause of that asymmetry. Publishing an API is a bigger commitment than calling one, and this is an early market on both sides. But the simplest explanation for near-zero external supply is that the on-ramp returned an error to everyone who tried it, and we should have caught it long before a user did.&lt;/p&gt;

&lt;p&gt;To be equally honest about the rest of the funnel, since it is the number that actually matters: those 21,155 trial calls correspond to 54 settled paid transactions and 3.522 USDC of real on-chain volume. Fixing the seller path does not fix that. Demand generation is a separate and harder problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we changed
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;AGENTS.md&lt;/code&gt;&lt;/strong&gt; — rewrote the publish section with the correct endpoint, full required-field list, and signing message. Explicitly marked the dead header-auth scheme as no longer honoured, so anyone who copied it earlier can tell why it stopped working.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;llms.txt&lt;/code&gt;, cookbook, MCP guide&lt;/strong&gt; — corrected every publish example and called out the undocumented &lt;code&gt;description&lt;/code&gt; minimum where developers will be looking when they hit it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;llms-full.txt&lt;/code&gt;&lt;/strong&gt; — a hand-written snapshot that had drifted, and was somehow &lt;em&gt;shorter&lt;/em&gt; than the summary it was meant to expand. Now generated from the live catalog hourly, with the 402 example captured from a real challenge at generation time rather than written by hand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CLI&lt;/strong&gt; — it had no publish command at all; its &lt;code&gt;register&lt;/code&gt; command is buyer-side, which is precisely the confusion the reporter hit. Added &lt;code&gt;publish&lt;/code&gt; with client-side validation so a missing description fails immediately with a legible message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing we did &lt;strong&gt;not&lt;/strong&gt; fix: the catalog does not record an HTTP method, so a service published to be called with POST reads back indistinguishably from a GET service and generic clients call it with GET. That is a gateway change, not a docs one. Until it ships it is written down, and the CLI warns about it after a successful publish. Naming a known defect beats letting a publisher discover it from silent failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  The general lesson
&lt;/h2&gt;

&lt;p&gt;If you run anything agents are supposed to use autonomously, the test is not "is the documentation good." The test is: &lt;strong&gt;can a machine that reads only your documentation complete the task?&lt;/strong&gt; That question has a yes-or-no answer, it can be checked automatically, and we were not checking it.&lt;/p&gt;

&lt;p&gt;The fix that generalizes is not "write better docs." It is to stop hand-maintaining files that describe a system that changes. Our discovery surface now regenerates from live state on a schedule, with examples captured from real responses. Anything still hand-written is a snapshot, and every snapshot drifts from the moment it is written.&lt;/p&gt;

&lt;p&gt;Ours drifted for weeks, in public, while telling agents exactly how to fail.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>ai</category>
      <category>programming</category>
    </item>
    <item>
      <title>Determinism Is the Product: What a 26-Endpoint Catalog Reveals About What Agents Pay For</title>
      <dc:creator>minia2a</dc:creator>
      <pubDate>Tue, 18 Aug 2026 18:27:05 +0000</pubDate>
      <link>https://dev.to/minia2a/determinism-is-the-product-what-a-26-endpoint-catalog-reveals-about-what-agents-pay-for-3mdf</link>
      <guid>https://dev.to/minia2a/determinism-is-the-product-what-a-26-endpoint-catalog-reveals-about-what-agents-pay-for-3mdf</guid>
      <description>&lt;p&gt;A one-person studio just launched a catalog of 26 pay-per-call APIs for AI agents — and the single most instructive endpoint in it is a &lt;strong&gt;hash function&lt;/strong&gt;. Not a model, not a data feed, not a "smart" anything. A deterministic &lt;code&gt;sha256&lt;/code&gt; wrapped in an x402 payment challenge.&lt;/p&gt;

&lt;p&gt;The reason it exists is the thesis of the whole catalog: &lt;em&gt;models generate strings that resemble valid cryptographic hashes but are not&lt;/em&gt;, and a wrong hash silently breaks webhook signature verification.&lt;/p&gt;

&lt;p&gt;That one sentence captures what the agent economy is about to pay for — &lt;strong&gt;determinism, not abundance&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 26-endpoint experiment
&lt;/h2&gt;

&lt;p&gt;The catalog is &lt;a href="https://underscoredone.com" rel="noopener noreferrer"&gt;_done&lt;/a&gt;, from One Scales — a solo builder shipping narrow, single-purpose APIs that machines call, not humans. Every endpoint is &lt;strong&gt;$0.01 per call, paid in USDC over x402 on Base or Solana&lt;/strong&gt;, with no accounts and no API keys: an agent requests an endpoint, receives an HTTP 402 payment challenge, signs a microtransaction from its wallet, and gets the result. That is the entire on-ramp.&lt;/p&gt;

&lt;p&gt;Look at what made the cut for those 26 slots:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;Why an agent can't just do it itself&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Hashing&lt;/td&gt;
&lt;td&gt;LLMs hallucinate plausible-but-wrong hashes; webhook verification needs the real bytes.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DNS / WHOIS lookup&lt;/td&gt;
&lt;td&gt;Deterministic resolution against live infrastructure, not a model's memory of a domain.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DMARC validation&lt;/td&gt;
&lt;td&gt;Email deliverability and spoofing checks need actual record parsing.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OCR&lt;/td&gt;
&lt;td&gt;Turning pixels into exact text — a perception task, not a generation task.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Screenshots / port scanning / sitemap extraction&lt;/td&gt;
&lt;td&gt;Ground truth about a live page or host, fetched now, not reconstructed.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;None of these are "data an LLM could guess." They are all &lt;strong&gt;verification against reality&lt;/strong&gt;: producing the exact bytes, the exact record, the exact text. That is the common thread, and it is why they can charge at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  The contrast that matters
&lt;/h2&gt;

&lt;p&gt;The market is currently obsessed with catalog size — how many endpoints a marketplace lists. But a catalog with a thousand endpoints where almost none get called teaches less than 26 endpoints each built around a determinism gap. The unit of value is not "one more API"; it is "one more thing the model cannot reliably do itself."&lt;/p&gt;

&lt;p&gt;This matches what the payment data already says. Keyrock's May 2026 report found &lt;strong&gt;76% of AI agent payments sit below Visa's $0.30 fixed-fee floor&lt;/strong&gt; — card rails are structurally incapable of settling a $0.01 hash lookup. Stablecoin micropayments are the only rail that fits, which is why every one of these deterministic endpoints settles in USDC. The pricing floor and the rail choice aren't separate decisions; they're the same decision.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we publish our own zeros
&lt;/h2&gt;

&lt;p&gt;The honest version of this story includes the unflattering numbers. Our own marketplace is serving &lt;strong&gt;817,324 total requests and 20,953 trial calls&lt;/strong&gt;, against &lt;strong&gt;86 on-chain transactions totaling 3.522 USDC&lt;/strong&gt;. Most of those 817K requests are crawlers, validators, and quote-cachers — the same shelf-placement traffic every x402 endpoint absorbs. The trial volume is real adoption; the settlement volume is the honest state of an early market.&lt;/p&gt;

&lt;p&gt;That gap is the signal. It says the scarce resource in machine-to-machine payments is not rails, not wallets, not discovery — it is &lt;strong&gt;things worth paying for&lt;/strong&gt;. And the things worth paying for, as _done's 26 endpoints show, are the ones that close a determinism gap: the hash, the DNS record, the DMARC check, the OCR'd receipt. Build one of those, price it at a penny, and you have a product. List a thousand guesses and you have a museum.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The takeaway:&lt;/strong&gt; don't optimize for how many endpoints you can surface — optimize for how many things you can make &lt;em&gt;exactly right&lt;/em&gt; that a model can't. Determinism is the product. Abundance is the noise.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;&lt;em&gt;Cross-posted from &lt;a href="https://minia2a.uk/blog/agent-pays-for-determinism-august-2026" rel="noopener noreferrer"&gt;minia2a.uk&lt;/a&gt;. minia2a is an open marketplace for x402 pay-per-call endpoints — 15 free trial calls per endpoint, 500 credits on registration, self-custody wallet, no KYC. Sources: One Scales _done launch (MarTech Series, Aug 17 2026); Keyrock agent-payments report (May 2026).&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>web3</category>
      <category>programming</category>
      <category>cryptocurrency</category>
    </item>
  </channel>
</rss>
