<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Michael Poyatt]]></title><description><![CDATA[Building digital payments]]></description><link>https://michaelpoyatt.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1767066498185/8fbe625c-5e2f-4bed-bf94-709407478c9a.png</url><title>Michael Poyatt</title><link>https://michaelpoyatt.com</link></image><generator>RSS for Node</generator><lastBuildDate>Fri, 17 Apr 2026 10:12:47 GMT</lastBuildDate><atom:link href="https://michaelpoyatt.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Why Crypto Payments Are Backwards]]></title><description><![CDATA[The Problem
If you’ve ever tried adding crypto payments to a traditional web app you may have noticed something odd. The standard approaches like WalletConnect and RainbowKit all execute transactions from your client-side code with a connection to th...]]></description><link>https://michaelpoyatt.com/why-crypto-payments-are-backwards</link><guid isPermaLink="true">https://michaelpoyatt.com/why-crypto-payments-are-backwards</guid><category><![CDATA[payments]]></category><category><![CDATA[x402]]></category><category><![CDATA[Blockchain]]></category><category><![CDATA[Web3]]></category><category><![CDATA[React]]></category><category><![CDATA[crypto]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Michael Poyatt]]></dc:creator><pubDate>Tue, 30 Dec 2025 04:00:59 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-the-problem">The Problem</h2>
<p>If you’ve ever tried adding crypto payments to a traditional web app you may have noticed something odd. The standard approaches like WalletConnect and RainbowKit all execute transactions from your client-side code with a connection to the user’s wallet. Then they try to tie this transaction to the user for your backend to process. This is often done in a convoluted way like generating a new wallet for every transaction. Hosted solutions like BitPay and Coinbase Commerce abstract away some complexity but still face the fundamental challenge of client-side transaction execution.</p>
<p>The problem in all these approaches is the lack of server-driven design. It’s like sending someone cash in the mail with no note attached and then trying to prove it was you who sent it.</p>
<h2 id="heading-how-i-stumbled-into-a-solution">How I Stumbled Into a Solution</h2>
<p>I wasn’t attempting to fix this. I wanted to learn more about the new <a target="_blank" href="https://www.x402.org/">x402</a> protocol with a hands-on project. I work at a crypto infrastructure startup where I added Stripe integration to accept payments, but we still weren’t accepting crypto-native payments. Two birds one stone.</p>
<p>Here’s the repo if you want to jump straight to the code: <a target="_blank" href="https://github.com/mvpoyatt/xtended402">xtended402</a></p>
<h2 id="heading-initial-approach">Initial Approach</h2>
<p>x402 v1 was designed specifically for agentic, high-volume, micro-payments. Using it to accept human-initiated, one-time payments of $100 on our dashboard meant breaking all three of those assumptions. The first thing I did was get rid of the “price discovery” phase, since the client here isn’t an AI agent that doesn’t know how to pay. It’s our own UI that knows exactly what the backend expects. Next I set up wallet connection and signature creation logic in the UI.</p>
<p>Backend integration was relatively simple using the Coinbase Go middleware, but your code will only be as reliable as the facilitator you’re using. We were building our own in-house facilitator so I integrated with that. Server ←→ facilitator interaction has two phases: verify the signature from the client is valid, then settle the transaction using the signature. The Coinbase middleware defaults to executing your happy-path logic after the verify phase succeeds but before waiting for the settle phase to succeed. While our in-house facilitator was still in development, the verify phase would succeed but the settle phase still failed. With the default middleware we would have been giving users free credits, so the final and most critical change was altering the Coinbase middleware to check the verify and settle calls before executing any code to process the order.</p>
<p>Done! Everything worked.</p>
<h2 id="heading-the-insight">The Insight</h2>
<p>I was excited that the experiment worked and we were accepting crypto payments in such an unusual way, but became much more intrigued when I started comparing it to the existing solutions.</p>
<p>The signature-based approach is completely server-driven. The client simply gets a signature from the user’s wallet, allowing the backend to drive payment logic. One drawback is the external dependency on a facilitator, but this is lower overhead than the existing hosted solutions and much more robust than the existing DIY solutions. You get:</p>
<ul>
<li><p>Server-authoritative pricing (no client manipulation)</p>
</li>
<li><p>Tight in-line link between customer and their transaction</p>
</li>
<li><p>Atomic order processing (payment confirmed before database writes)</p>
</li>
<li><p>Standard REST patterns</p>
</li>
</ul>
<p>The key shift here isn’t really about x402. It’s about using EIP-3009 signatures to process payments server-side. x402 establishes a consistent pattern and it’s facilitators provide a uniform way to abstract out some of the on-chain complexity - a nice balance between open-source and easy-to-implement. But a web-app or online store could implement this same pattern in another way, getting signatures from the client and writing their own execution logic for the backend, while the customer data is still in the request context.</p>
<h2 id="heading-the-solution">The Solution</h2>
<p>Based on this insight <a target="_blank" href="https://github.com/mvpoyatt/xtended402">I created a library</a> to make this pattern accessible.</p>
<p><strong>Core Features:</strong></p>
<ul>
<li><p>Go middleware with configurable settlement timing (process before or after payment)</p>
</li>
<li><p>Context-based dynamic pricing from request bodies (shopping carts)</p>
</li>
<li><p>React component that handles the entire payment flow</p>
</li>
<li><p>Maintains Full x402 v2 compatibility</p>
</li>
</ul>
<p><strong>The React Checkout component in action:</strong></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1767065433341/8e5210de-bbce-49ec-9a49-396e42c5f194.gif" alt="Animated demo showing a React component facilitating a crypto signature and backend settlement." class="image--center mx-auto" /></p>
<h2 id="heading-how-this-evolved">How This Evolved</h2>
<p>After a lot of back-and-forth I decided to keep the library x402 compatible. As previously mentioned, x402 standards aren’t specifically necessary for server-side transaction execution, but I figured why narrow when I could expand. Now one endpoint can accept payment from a human-driven UI or an AI agent.</p>
<p>I spent a couple weeks building a solution for v1 of x402. Then, less than twelve hours after finishing, Coinbase released <a target="_blank" href="https://www.x402.org/writing/x402-v2-launch">v2</a>. The good news was that it included some of the changes I made and validated the direction I was heading in. It’s more chain/token agnostic (uses CAIP-2 identifiers) and there’s even a React button example in their documentation, acknowledging human payments. The architecture is fundamentally more modular and extension-friendly as well.</p>
<p>v2 also introduced support for dynamic pricing but it’s designed to be implemented using request headers. This can get unwieldy when working with more complex data structures like a shopping cart order that determine price. The <a target="_blank" href="https://github.com/mvpoyatt/xtended402">xtended402 repo</a> includes some helpers to make it easier to determine the price based on the request body, store it in the request context and then tell the middleware to use that price.</p>
<p>The issue I experienced with settlement timing still wasn’t fully addressed, so I created another version of the Go middleware with a parameter to make that configurable (<code>WithSettlementTiming</code>). The other tools in this repo can be used with the standard Coinbase x402 middleware, but for physical goods or expensive products it’s important to ensure that the payment is processed and that the customer receives their order. The repo also includes <a target="_blank" href="https://github.com/mvpoyatt/xtended402/tree/main/server/go">code examples for best practices</a> on how to ensure order integrity.</p>
<p>The React component uses the price discovery phase to learn what payment the backend accepts, ensure it’s a token that supports EIP-3009 signatures, connect to that chain in the user’s wallet, display the appropriate token balance and show the price as determined by the backend. No need to hard-code prices in to the front-end, just plug in the payment URL and let server tell the client how to pay.</p>
<h2 id="heading-whats-next">What’s Next</h2>
<p>xtended402 is open source so that more devs can try this pattern out, more quickly. Crypto payments don’t need to be harder than traditional payments—they're just backwards now.</p>
<p><a target="_blank" href="https://github.com/mvpoyatt/xtended402">Check out the repo here</a> - I'd love feedback, contributions, or to hear if you've faced similar problems. I also have open issues for what I’m thinking about next.</p>
<p><a target="_blank" href="https://github.com/mvpoyatt/xtended402/tree/main/examples">Try it yourself</a> - The repo includes a full-stack example you can get running locally in minutes.</p>
<p>This pattern is working well for our use case, but every payment flow is different. Feel free to fork it, break it, or tell me why I'm wrong.</p>
]]></content:encoded></item></channel></rss>