<?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: vet402</title>
    <description>The latest articles on DEV Community by vet402 (@kzmttkc).</description>
    <link>https://dev.to/kzmttkc</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%2F4241926%2F128ae623-6329-49ec-83a1-e42bef44aee1.png</url>
      <title>DEV Community: vet402</title>
      <link>https://dev.to/kzmttkc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kzmttkc"/>
    <language>en</language>
    <item>
      <title>x402 returned 202 after payment? Data from 14,991 paid calls, and how refunds work</title>
      <dc:creator>vet402</dc:creator>
      <pubDate>Sat, 14 Nov 2026 04:33:28 +0000</pubDate>
      <link>https://dev.to/kzmttkc/x402-returned-202-after-payment-data-from-14991-paid-calls-and-how-refunds-work-2jhk</link>
      <guid>https://dev.to/kzmttkc/x402-returned-202-after-payment-data-from-14991-paid-calls-and-how-refunds-work-2jhk</guid>
      <description>&lt;p&gt;An agent pays an x402 seller, the payment settles, and the seller answers 202 Accepted. Code that checks only &lt;code&gt;res.ok&lt;/code&gt; marks the task done. vet402 does not count a 202 as delivery. In the ledger below, 202s are part of the 510 settled calls that returned nothing usable.&lt;/p&gt;

&lt;p&gt;I'm Sen, and I build vet402. vet402 pays x402 sellers from its own wallets and records what each paid call returned. This post shows what those calls returned and why a 202 still gets charged. Then it shows a check an agent can run before it signs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What 14,991 settled x402 payments returned
&lt;/h2&gt;

&lt;p&gt;As of Nov 13, 2026 (UTC), the ledger holds 14,991 settled payments. 13,721 of them came back with content, meaning a 2xx other than 202 with a non-empty body.&lt;/p&gt;

&lt;p&gt;510 settled payments came back with no usable content. Most had no HTTP status on record, a 5xx, or a 202 Accepted. Another 760 settled calls got a 4xx. They are not in the 510. A 4xx after payment often means the request was missing a field the seller wanted, so read the seller's 402 for the input it declares.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a 202 still gets charged
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/x402-foundation/x402/tree/main/specs/schemes/exact" rel="noopener noreferrer"&gt;exact spec&lt;/a&gt; says the default flow settles only after the handler succeeds. In the &lt;a href="https://github.com/x402-foundation/x402/blob/main/typescript/packages/http/express/src/index.ts" rel="noopener noreferrer"&gt;reference Express middleware&lt;/a&gt;, success means any status below 400. The check is &lt;code&gt;if (res.statusCode &amp;gt;= 400)&lt;/code&gt; in &lt;code&gt;typescript/packages/http/express/src/index.ts&lt;/code&gt;, and it cancels settlement. A 500 leaves the buyer uncharged. A 202 or an empty 200 is below 400, so it settles.&lt;/p&gt;

&lt;p&gt;Under &lt;code&gt;exact&lt;/code&gt;, a settled payment comes back only if the seller sends a new transfer. The &lt;a href="https://github.com/x402-foundation/x402/tree/main/specs/schemes/auth-capture" rel="noopener noreferrer"&gt;&lt;code&gt;auth-capture&lt;/code&gt;&lt;/a&gt; scheme adds two paths. The seller can void or refund. The buyer can reclaim a hold that was never captured once the capture deadline passes, without the seller. The rules for each scheme are at &lt;a href="https://vet402.com/x402/refunds" rel="noopener noreferrer"&gt;https://vet402.com/x402/refunds&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;An agent can run the next check on its own, before it signs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check a seller before paying
&lt;/h2&gt;

&lt;p&gt;vet402 publishes what came back each time it paid a given URL. The REST endpoint needs no key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl -G https://vet402.com/api/v1/check \
  --data-urlencode &lt;span class="s2"&gt;"url=https://seller.example/api/quote"&lt;/span&gt; \
  --data-urlencode &lt;span class="s2"&gt;"method=POST"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A URL vet402 has never seen comes back with &lt;code&gt;not_in_catalog: true&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The response has a &lt;code&gt;recommendation&lt;/code&gt; and a &lt;code&gt;delivery&lt;/code&gt; block. &lt;code&gt;delivery&lt;/code&gt; counts paid attempts, deliveries, and settled calls that did not deliver. &lt;code&gt;l1_purchases&lt;/code&gt; lists the latest purchases, each with an explorer link.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;verified_terms&lt;/code&gt; holds &lt;code&gt;pay_to&lt;/code&gt;, &lt;code&gt;asset&lt;/code&gt;, &lt;code&gt;amount&lt;/code&gt;, &lt;code&gt;network&lt;/code&gt; and &lt;code&gt;scheme&lt;/code&gt; from the last purchase vet402 saw delivered. If the 402 in hand differs in any of those, or asks for more, it is a different offer. &lt;code&gt;amount&lt;/code&gt; is in 6-decimal units, so multiply it by 10^12 on BNB Chain and by 10 on Stellar before you compare.&lt;/p&gt;

&lt;p&gt;An agent can run the same lookup through the hosted MCP server before each payment:&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="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;"vet402"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"https://vet402.com/mcp"&lt;/span&gt; &lt;span class="p"&gt;}&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;The tool is &lt;code&gt;check_x402_seller&lt;/code&gt;. &lt;code&gt;check_payment_proof&lt;/code&gt; reads a payment already made, and &lt;code&gt;find_x402_sellers&lt;/code&gt; lists sellers vet402 paid and got content from in the last 30 days. If you sell over x402, &lt;code&gt;check_my_x402_endpoint&lt;/code&gt; shows what vet402 saw when it paid your endpoint.&lt;/p&gt;

&lt;h2&gt;
  
  
  Decide delivery in the agent's own code
&lt;/h2&gt;

&lt;p&gt;Whichever seller an agent picks, two checks after the call keep it from counting any of the 510 cases above as delivered:&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="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;res&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;paidFetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// your x402-wrapped fetch&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;delivered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;202&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;settlement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="n"&gt;res&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="s2"&gt;"PAYMENT-RESPONSE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="n"&gt;res&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="s2"&gt;"X-PAYMENT-RESPONSE"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;requestId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;delivered&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;settlement&lt;/span&gt; &lt;span class="p"&gt;}&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;ol&gt;
&lt;li&gt;Mark the task done only when &lt;code&gt;delivered&lt;/code&gt; is true. If the seller documents a job URL in its 202, poll it and mark done when the result arrives.&lt;/li&gt;
&lt;li&gt;Keep the settlement header next to the request id. If the seller offers auth-capture or its own refund path, that pair is what it will ask for.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Put those two checks in the agent's payment wrapper, and run &lt;code&gt;check_x402_seller&lt;/code&gt; before the first payment to any new seller.&lt;/p&gt;

&lt;h2&gt;
  
  
  The data
&lt;/h2&gt;

&lt;p&gt;The full purchase ledger is public under CC BY 4.0. The live CSV is at &lt;a href="https://vet402.com/api/v1/observatory/export.csv?days=366" rel="noopener noreferrer"&gt;https://vet402.com/api/v1/observatory/export.csv?days=366&lt;/a&gt; and a dated snapshot is archived on Zenodo at &lt;a href="https://doi.org/10.5281/zenodo.24195171" rel="noopener noreferrer"&gt;https://doi.org/10.5281/zenodo.24195171&lt;/a&gt;. The method behind each column is at &lt;a href="https://vet402.com/observatory/methodology" rel="noopener noreferrer"&gt;https://vet402.com/observatory/methodology&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you run an x402 seller and a row about your endpoint looks wrong, write to &lt;a href="mailto:support@vet402.com"&gt;support@vet402.com&lt;/a&gt;. Corrections are published at &lt;a href="https://vet402.com/corrections" rel="noopener noreferrer"&gt;https://vet402.com/corrections&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>x402</category>
      <category>ai</category>
      <category>webdev</category>
      <category>web3</category>
    </item>
  </channel>
</rss>
