<?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: Нико Лайф</title>
    <description>The latest articles on DEV Community by Нико Лайф (@nikolife).</description>
    <link>https://dev.to/nikolife</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%2F4034694%2Fc46d87e7-d134-418a-aa39-3fa324c00e28.jpg</url>
      <title>DEV Community: Нико Лайф</title>
      <link>https://dev.to/nikolife</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikolife"/>
    <language>en</language>
    <item>
      <title>76% dead was my bug, not the market's — and then I made four more mistakes exactly like it</title>
      <dc:creator>Нико Лайф</dc:creator>
      <pubDate>Thu, 30 Jul 2026 17:25:17 +0000</pubDate>
      <link>https://dev.to/nikolife/76-dead-was-my-bug-not-the-markets-and-then-i-made-four-more-mistakes-exactly-like-it-1pbc</link>
      <guid>https://dev.to/nikolife/76-dead-was-my-bug-not-the-markets-and-then-i-made-four-more-mistakes-exactly-like-it-1pbc</guid>
      <description>&lt;p&gt;Two weeks ago I published an audit of the x402 agent-payment economy with the headline finding that &lt;strong&gt;76% of listed endpoints were dead or invalid&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That number was wrong. It was measuring my own parser.&lt;/p&gt;

&lt;p&gt;The real figure is &lt;strong&gt;38%&lt;/strong&gt;. Not because the ecosystem recovered — because my prober had been reading the wrong half of the HTTP response. This post is the correction, the mechanism, and the four &lt;em&gt;additional&lt;/em&gt; mistakes I made in the same family while fixing the first one. That last part is the useful bit.&lt;/p&gt;

&lt;p&gt;Everything here is reproducible with &lt;code&gt;curl&lt;/code&gt;. Commands are inline.&lt;/p&gt;




&lt;h2&gt;
  
  
  The mistake
&lt;/h2&gt;

&lt;p&gt;x402 puts payment requirements in a &lt;code&gt;402 Payment Required&lt;/code&gt; response. In v1 they live in the JSON body:&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"x402Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&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;"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="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"maxAmountRequired"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10000"&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="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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In v2 they moved into a &lt;strong&gt;&lt;code&gt;PAYMENT-REQUIRED&lt;/code&gt; response header&lt;/strong&gt; (base64-encoded JSON), and the body became a server implementation detail. Many v2 services return a body with no &lt;code&gt;accepts&lt;/code&gt; at all — sometimes just &lt;code&gt;{}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;My prober only parsed the body. So a live v2 service looked like this: HTTP 402 received, no &lt;code&gt;accepts&lt;/code&gt; found, verdict &lt;code&gt;malformed&lt;/code&gt;, public advice &lt;strong&gt;"do not pay: dead or invalid."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here is one of them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sD&lt;/span&gt; - &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null https://api.onesource.io/api/chain/block-number &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'^payment-required'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/^[^:]*: //'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A complete, valid challenge: &lt;code&gt;scheme: exact&lt;/code&gt;, network &lt;code&gt;eip155:8453&lt;/code&gt;, &lt;code&gt;amount: 1000&lt;/code&gt; (0.001 USDC), a real &lt;code&gt;payTo&lt;/code&gt;. The service works. It always worked. My oracle told agents it was dead, with a trust score of 8 out of 100 and 0% uptime.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1,869 endpoints across 166 operators&lt;/strong&gt; were in that state. Among them, &lt;code&gt;pro-api.coingecko.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I also owed a catalog an apology. I had been publishing that 402index overstates health — that only ~30% of what it lists as "healthy" really is. After the fix, the same comparison gives &lt;strong&gt;~68%&lt;/strong&gt; (live figure in &lt;code&gt;catalogAudit.accuracyPct&lt;/code&gt; at &lt;a href="https://pulsefeed.dev/status.json" rel="noopener noreferrer"&gt;/status.json&lt;/a&gt; — it moves with each crawl). The catalog was substantially more honest than I said it was. Mine was the unreliable measurement.&lt;/p&gt;




&lt;h2&gt;
  
  
  The fix, and what it cost
&lt;/h2&gt;

&lt;p&gt;Fixing the parser was ten lines: read the body, read the header, prefer the header (that is what a v2 client pays against), record which one carried the challenge.&lt;/p&gt;

&lt;p&gt;The expensive part was history. My uptime metric is the share of past observations with a &lt;code&gt;healthy&lt;/code&gt; verdict, and for these services every past observation said &lt;code&gt;malformed&lt;/code&gt;. That is not their downtime — it is my bug, recorded as their track record. I removed &lt;strong&gt;3,920&lt;/strong&gt; &lt;code&gt;malformed&lt;/code&gt; history entries from 1,869 endpoints that now return a valid header challenge, kept every &lt;code&gt;unreachable&lt;/code&gt; and &lt;code&gt;no-402&lt;/code&gt; entry (my bug could not produce those), and stamped each repaired record with &lt;code&gt;historyRepairedAt&lt;/code&gt;, &lt;code&gt;historyRepairedEntries&lt;/code&gt; and a note. Those markers are in the free &lt;code&gt;/verify&lt;/code&gt; response, so anyone reading a track record can see it was edited and why.&lt;/p&gt;

&lt;p&gt;Which created a new problem: services with one observation and a "100% uptime" badge. So uptime is now &lt;code&gt;null&lt;/code&gt; below three observations with an explicit &lt;code&gt;insufficient&lt;/code&gt; confidence flag, and the trust score no longer grants full uptime credit on a thin history. A track record you cannot state is better than one you invent.&lt;/p&gt;

&lt;p&gt;The daily time series had the same hazard. Live endpoints went 1,452 → 3,487 in one snapshot. Any reader — including future me — would see a market doubling overnight. Each snapshot now carries &lt;code&gt;probeVersion&lt;/code&gt;, and day-over-day deltas across a version boundary are suppressed with a stated reason instead of rendered as green arrows.&lt;/p&gt;

&lt;p&gt;Current numbers, checkable right now:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pulsefeed.dev/status.json | jq &lt;span class="s1"&gt;'.ecosystem'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Then I made four more mistakes of exactly the same kind
&lt;/h2&gt;

&lt;p&gt;This is the part I would want to read.&lt;/p&gt;

&lt;p&gt;Having just been burned by a parser that knew less than the spec, I added detectors for endpoints that return a valid 402 but still are not payable products. Within hours, three of them were wrong, in the same way, for the same reason: &lt;strong&gt;my code encoded my assumption about the protocol instead of the protocol.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. I called a standard scheme unpayable
&lt;/h3&gt;

&lt;p&gt;I decided the only settleable scheme was &lt;code&gt;exact&lt;/code&gt;, flagged everything else as "no standard client can settle this — funds leave escrow, irreversibly," and published it at high severity.&lt;/p&gt;

&lt;p&gt;The x402 spec has four schemes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.github.com/repos/x402-foundation/x402/contents/specs/schemes &lt;span class="se"&gt;\&lt;/span&gt;
  | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.[] | select(.type=="dir") | .name'&lt;/span&gt;
&lt;span class="c"&gt;# auth-capture, batch-settlement, exact, upto&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The service I flagged, &lt;code&gt;api.bitrefill.com/x402/invoice/pay&lt;/code&gt;, uses &lt;code&gt;upto&lt;/code&gt; — a normal scheme, in the spec, and by on-chain volume one of the largest receivers in the ecosystem. Three separate claims in my alert were false. I had reproduced my own bug against a different protocol field.&lt;/p&gt;

&lt;p&gt;The real distinction is not payable versus unpayable:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;outside the spec&lt;/strong&gt; → settlement does not go through a facilitator, funds are not in escrow — worth flagging;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;in the spec but not &lt;code&gt;exact&lt;/code&gt;&lt;/strong&gt; → a default &lt;code&gt;x402-fetch&lt;/code&gt; client cannot pay it without work. That is a compatibility note, not an accusation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One endpoint in my index is genuinely outside the spec: &lt;code&gt;api.dynsuplabs.com&lt;/code&gt; advertises &lt;code&gt;exact-prepay-proof&lt;/code&gt;, and its own &lt;code&gt;extra.doc&lt;/code&gt; field instructs the client to broadcast the USDC transfer itself, outside any facilitator, stating that payment is final and non-refundable. That one deserved a flag. The other did not.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. I read an authorization ceiling as a price
&lt;/h3&gt;

&lt;p&gt;Same service, second false alarm. Its challenge carries &lt;code&gt;amount: 1000000000&lt;/code&gt; — 1,000 USDC. My price detector saw a thousand-dollar API call and flagged "absurd price."&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;upto&lt;/code&gt;, &lt;code&gt;amount&lt;/code&gt; is the &lt;strong&gt;maximum the service is authorized to draw&lt;/strong&gt;, not the price of a call. It is a gift-card purchase flow; the actual charge is usage-based. Comparing a ceiling against other services' per-call prices means comparing two different quantities and calling the difference fraud.&lt;/p&gt;

&lt;p&gt;Ceilings now live in a separate field with an explicit note — never in the price field, never in price comparisons.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. I described a mechanism I never tested
&lt;/h3&gt;

&lt;p&gt;Hundreds of listed URLs are documentation placeholders — &lt;code&gt;/api/chain/tx/:hash&lt;/code&gt;, &lt;code&gt;/v1/{id}&lt;/code&gt;, &lt;code&gt;/example&lt;/code&gt; — that still return a valid 402. I wrote that the 402 is served "by middleware before the route is resolved," and that a paying agent "gets a 404."&lt;/p&gt;

&lt;p&gt;Both were guesses. Requesting a genuinely nonexistent path on the same hosts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code}\n'&lt;/span&gt; https://skills.onesource.io/api/chain/zzz-not-real-route    &lt;span class="c"&gt;# 308&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s1"&gt;'%{http_code}\n'&lt;/span&gt; https://api.gocreativeai.com/definitely-not-a-real-zzz999   &lt;span class="c"&gt;# 502&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not 402. So the route &lt;em&gt;did&lt;/em&gt; match — the placeholder was accepted as a parameter value. And what a payer receives I do not know, because I never paid. The claim is now limited to what is observable: the URL is a string from documentation, the challenge is valid, and catalogs count it as a live service.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. I attached intent to companies I had just proven myself wrong about
&lt;/h3&gt;

&lt;p&gt;My public feed labeled named, identifiable businesses with "bait-and-switch pricing," "price gouging," "honeypot receiver," "possible hijack." In the US the first two carry statutory and FTC meaning; all four assert intent. I cannot demonstrate intent from an HTTP response — and I had just been wrong about the mechanism three times in one day.&lt;/p&gt;

&lt;p&gt;Labels now describe the observation. "Advertised price differs from the amount actually requested." "Receiver address changed between observations," with the note that routine key rotation and a compromise are indistinguishable from outside. A high price now carries "may be entirely legitimate for what it returns — we measure the number, not its fairness."&lt;/p&gt;




&lt;h2&gt;
  
  
  What "live" actually means
&lt;/h2&gt;

&lt;p&gt;Every one of these mistakes came from treating &lt;em&gt;"returned a 402"&lt;/em&gt; as if it meant &lt;em&gt;"is a payable product."&lt;/em&gt; It does not. Here is the checklist I run now, written so you can apply it to your own index. Copy it.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Why it exists&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Parse the challenge from &lt;strong&gt;both&lt;/strong&gt; the body and the &lt;code&gt;PAYMENT-REQUIRED&lt;/code&gt; header, preferring the header&lt;/td&gt;
&lt;td&gt;v2 moved it; body-only readers see live services as broken&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Compare the two when both are present&lt;/td&gt;
&lt;td&gt;If they disagree, a v2 client pays what the &lt;strong&gt;header&lt;/strong&gt; says — which is not what a body-only check displays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Check the scheme against &lt;code&gt;specs/schemes/&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Outside the spec means settlement bypasses the facilitator; in-spec-but-not-&lt;code&gt;exact&lt;/code&gt; is a client compatibility matter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Know whether &lt;code&gt;amount&lt;/code&gt; is a price or a ceiling&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;upto&lt;/code&gt; and &lt;code&gt;auth-capture&lt;/code&gt; state a maximum, not a per-call cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Check that the network is mainnet&lt;/td&gt;
&lt;td&gt;A testnet sandbox priced in dollars is not a product&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Check the URL for unfilled path placeholders&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;:id&lt;/code&gt;, &lt;code&gt;{id}&lt;/code&gt;, &lt;code&gt;/example&lt;/code&gt; are documentation strings&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Know the token's decimals per chain&lt;/td&gt;
&lt;td&gt;USDC is 6 decimals on most chains and &lt;strong&gt;18 on BSC&lt;/strong&gt;; assuming 6 everywhere is a 10¹² error&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;Count distinct operators, not endpoints&lt;/td&gt;
&lt;td&gt;One host can list hundreds of routes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;9&lt;/td&gt;
&lt;td&gt;State the observation count next to any uptime figure&lt;/td&gt;
&lt;td&gt;A percentage over one observation is not a track record&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;Version your measurement method and mark the break&lt;/td&gt;
&lt;td&gt;Otherwise your own fixes read as market movement&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What my own numbers look like under that checklist
&lt;/h2&gt;

&lt;p&gt;The same discipline, applied to me. My index currently reports 3,487 live endpoints. Inside that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;682&lt;/strong&gt; are documentation placeholders — and honesty requires the next sentence: &lt;strong&gt;582 of them are a single host&lt;/strong&gt;, &lt;code&gt;api.gocreativeai.com&lt;/code&gt;. Without it, 100 placeholders across 22 domains. Reporting "682 across 23 domains" and stopping there would be exactly the inflation I criticize.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;29&lt;/strong&gt; are on test networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; advertises a scheme outside the spec.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1&lt;/strong&gt; has a body/header disagreement.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Honest remainder: &lt;strong&gt;2,775 endpoints across 338 operators.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;And those 3,487 endpoints resolve to only &lt;strong&gt;350 distinct hosts&lt;/strong&gt;, with the top three accounting for 1,575 of them. This is a far narrower ecosystem than any endpoint count suggests.&lt;/p&gt;

&lt;p&gt;Other limits, stated plainly: my observations begin 2026-07-06, which is shallow. Other trackers have deeper history and broader coverage — &lt;code&gt;x402.fuchss.app&lt;/code&gt; publishes on-chain data complete since 2025-05-09 across roughly 97k listed endpoints, and it separates reachability from envelope compliance, which is precisely the distinction I got wrong. Where our numbers differ, the longer series is more likely to be right about trends. I am confident only about what I can re-probe today.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verify everything here yourself
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ecosystem totals, composition, catalog comparison&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pulsefeed.dev/status.json | jq &lt;span class="s1"&gt;'.ecosystem, .catalogAudit'&lt;/span&gt;

&lt;span class="c"&gt;# one endpoint, free&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'https://pulsefeed.dev/verify?endpoint=https://api.onesource.io/api/chain/block-number'&lt;/span&gt; | jq

&lt;span class="c"&gt;# every anomaly currently observed, with on-chain references&lt;/span&gt;
curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://pulsefeed.dev/incidents.json | jq &lt;span class="s1"&gt;'.byCategory'&lt;/span&gt;

&lt;span class="c"&gt;# the v2 header, straight from the source&lt;/span&gt;
curl &lt;span class="nt"&gt;-sD&lt;/span&gt; - &lt;span class="nt"&gt;-o&lt;/span&gt; /dev/null https://api.onesource.io/api/chain/block-number &lt;span class="se"&gt;\&lt;/span&gt;
  | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="s1"&gt;'^payment-required'&lt;/span&gt; | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/^[^:]*: //'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; | jq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dataset is CC-BY-4.0 on &lt;a href="https://huggingface.co/datasets/Nikolife/pulsefeed-x402-security" rel="noopener noreferrer"&gt;Hugging Face&lt;/a&gt;. The original article now carries a correction notice at the top, archived daily reports produced by the old prober carry a banner telling readers not to cite their liveness numbers, and &lt;code&gt;/llms.txt&lt;/code&gt; carries a machine-readable correction beside the link.&lt;/p&gt;

&lt;p&gt;If you run a catalog, a wallet, or an agent that decides whether to pay an endpoint: run check #1 today. It is ten lines, and in your own dashboard it is the difference between a live ecosystem and a mostly-dead one.&lt;/p&gt;

&lt;p&gt;If you find an error in this post, tell me. That is now demonstrably the fastest way to improve this dataset.&lt;/p&gt;

</description>
      <category>postmortem</category>
      <category>ai</category>
      <category>security</category>
      <category>web3</category>
    </item>
    <item>
      <title>I audited the entire x402 agent-payment economy. 76% is dead — and the live half has scams.</title>
      <dc:creator>Нико Лайф</dc:creator>
      <pubDate>Sat, 18 Jul 2026 04:38:11 +0000</pubDate>
      <link>https://dev.to/nikolife/i-audited-the-entire-x402-agent-payment-economy-76-is-dead-and-the-live-half-has-scams-2ljc</link>
      <guid>https://dev.to/nikolife/i-audited-the-entire-x402-agent-payment-economy-76-is-dead-and-the-live-half-has-scams-2ljc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;CORRECTION — 2026-07-30.&lt;/strong&gt; The headline figure in this article is wrong. The "76% dead" number measured my own prober, not the ecosystem: it read x402 payment requirements only from the HTTP response body, while x402 v2 moved them into the &lt;code&gt;PAYMENT-REQUIRED&lt;/code&gt; header. 1,869 endpoints across 166 operators were live and recorded as dead. The corrected figure is 38%. Full write-up of the mechanism, the four further mistakes I made while fixing it, and a checklist for deciding whether an endpoint is genuinely payable: &lt;strong&gt;&lt;a href="https://pulsefeed.dev/correction" rel="noopener noreferrer"&gt;https://pulsefeed.dev/correction&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The scam and anomaly findings below are unaffected; the liveness numbers are not reliable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;x402 is the protocol everyone in the AI-agent space is excited about: HTTP 402 Payment Required + stablecoins, so an AI agent can pay for an API call autonomously, no accounts, no API keys — the wallet is the identity. Coinbase, Cloudflare, Stripe, AWS and Google have all shipped support. The narrative is enormous.&lt;/p&gt;

&lt;p&gt;So I did the boring thing: I pointed a crawler at every x402 endpoint I could find and actually probed them. Then I kept probing them, every day, and recorded what changed.&lt;/p&gt;

&lt;p&gt;The results are not what the narrative suggests.&lt;/p&gt;

&lt;p&gt;Finding #1: most of it is dead&lt;br&gt;
Of 5,077 tracked x402 endpoints, ~76% are dead or invalid — they don't return a valid x402 payment challenge when you actually call them. Of what's left, only about half of the endpoints that public catalogs label "healthy" actually work under a strict probe.&lt;/p&gt;

&lt;p&gt;Strip the duplicates (a handful of providers list hundreds of endpoints each) and you're left with roughly 135 genuinely live services. The agentic-payment economy is real, but it's small, and a lot of what's listed is noise.&lt;/p&gt;

&lt;p&gt;Finding #2: the live half has a scam problem&lt;br&gt;
Dead endpoints waste an agent's time. The live ones can waste its money — and x402 payments are irreversible. There's no chargeback for an autonomous agent.&lt;/p&gt;

&lt;p&gt;Probing continuously surfaces a recurring set of failure modes. Right now there are 35 active incidents, 18 of them high-severity, across a few categories:&lt;/p&gt;

&lt;p&gt;Bait-and-switch pricing — the endpoint advertises one price in its x402 challenge, then requires a different amount at payment. Example caught live: headlessoracle.com (receiver 0x26D4…0AD3), plus agents.dyoeway.org and lionx402.com doing the same thing. An agent that trusts the advertised price pays the higher one.&lt;/p&gt;

&lt;p&gt;Receiver hijack — the payTo address silently changes on an endpoint that previously had a stable, established receiver. Maybe it's the operator rotating keys; maybe it's a compromise. Either way, an agent that paid it yesterday should re-verify before paying it today.&lt;/p&gt;

&lt;p&gt;Honeypot receivers — a zero or malformed payTo. Money sent here is simply gone.&lt;/p&gt;

&lt;p&gt;Unverified receivers — a payTo with no on-chain USDC history at all. Not proof of fraud, but a real risk signal: nobody has ever actually paid this address, yet it's asking your agent to be the first.&lt;/p&gt;

&lt;p&gt;Price gouging — anomalously high prices relative to the rest of the ecosystem. Example: x721.dev at $40.20 per call while comparable services charge fractions of a cent.&lt;/p&gt;

&lt;p&gt;Every one of these is linked to on-chain proof you can verify yourself — the receiver address on Base, open in a block explorer. I'm not asking you to trust my verdict; the evidence is public.&lt;/p&gt;

&lt;p&gt;An honesty note (this matters)&lt;br&gt;
I state findings as facts from the data, not as accusations of intent:&lt;/p&gt;

&lt;p&gt;"bait-and-switch" = advertised price ≠ amount actually charged (observable).&lt;br&gt;
"unverified receiver" = payTo has no on-chain USDC history (a risk signal, not a conviction).&lt;br&gt;
"possible hijack" = the receiver changed on an established baseline — could be a legitimate key rotation.&lt;br&gt;
By-design receiver rotation (some services rotate a per-session address on purpose) is excluded so it doesn't pollute the signal. If you're going to publish security findings about named services, you have to be precise, or you're just spreading FUD.&lt;/p&gt;

&lt;p&gt;Why nobody had this data&lt;br&gt;
Here's the part that's structurally interesting. You cannot reconstruct this after the fact. "This endpoint's payTo changed three times last month," "this receiver has been stable for 60 days," "this price crept up 4×" — none of it exists unless someone was watching continuously and writing it down as it happened. A snapshot taken today can't tell you what an endpoint was.&lt;/p&gt;

&lt;p&gt;That's the whole game with trust: it's accumulated history, and history can't be back-filled. A catalog can list what's live right now. It can't tell you what's trustworthy over time.&lt;/p&gt;

&lt;p&gt;It's not just x402 — MCP has the same shape&lt;br&gt;
The same independent-audit lens applied to the MCP (Model Context Protocol) server ecosystem finds a parallel problem: of 938 audited MCP servers, ~11% run an arbitrary install script on npm i (code execution the moment you connect them), dozens are abandoned, and 85 ship no repository to review at all. Install scripts aren't always malicious — native builds use them — but each is an unreviewed code-execution vector, and most people connect a server without ever checking.&lt;/p&gt;

&lt;p&gt;Different protocol, same failure: the tooling shipped faster than the trust layer.&lt;/p&gt;

&lt;p&gt;What to actually do about it&lt;br&gt;
If you're building agents that pay for things or connect to tools:&lt;/p&gt;

&lt;p&gt;Verify before you pay. Don't let an agent pay an x402 endpoint it hasn't checked for liveness, price consistency, and receiver sanity. A free check: GET &lt;a href="https://pulsefeed.dev/trust?endpoint=" rel="noopener noreferrer"&gt;https://pulsefeed.dev/trust?endpoint=&lt;/a&gt; → verdict + on-chain receiver profile + scam flags.&lt;br&gt;
Verify before you connect. Same for MCP servers: GET &lt;a href="https://pulsefeed.dev/mcp/verify?package=" rel="noopener noreferrer"&gt;https://pulsefeed.dev/mcp/verify?package=&lt;/a&gt; before you install.&lt;br&gt;
Watch what changes. A safe endpoint can be hijacked or repriced overnight. The live incident feed is free to read: pulsefeed.dev/incidents (also as RSS if you want a machine to watch it).&lt;br&gt;
The audit, the incident feed, the ecosystem reports and the methodology are all free and public — I built PulseFeed because I needed this data to exist and it didn't. There's a paid cross-domain data feed for people building trust/monitoring tools, but you don't need to pay anything to check an endpoint or read the incidents.&lt;/p&gt;

&lt;p&gt;The agent economy is coming. The trust layer under it is mostly not built yet. That's the interesting problem — and right now, most of what's live is worth being suspicious of.&lt;/p&gt;

&lt;p&gt;Data as of the latest daily crawl. Methodology: pulsefeed.dev/methodology. Live disclosures with on-chain proof: pulsefeed.dev/incidents.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd0nd5bwewkfg1fwd9plf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd0nd5bwewkfg1fwd9plf.png" alt=" " width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
