X402, a static blog monetization excercise

morty281 pts0 comments

x402, a static blog monetization excercise

x402, a static blog monetization excercise

on 2026-07-05

x402

Cloudflare has published an announcement couple of days ago about Monetization Gateway launch.<br>This is revolutionary for many reasons. It removes the high entry barrier for monetization, it lets you have a very precise control over what you charge for and how low the payment can be.<br>This literally can change how we use internet making advertisement economy internet runs on obsolete.

It sounds like an ideal tool to monetize a blog, or an API, for example. And even though I don't have anything to monetize, the technology seems too important for me not to try it out. So let's do just that.

The plan

Unfortunately the Cloudflare service still seems to be in a closed beta(?), meaning you can't get access to it freely as of now, you need to join a waitlist. So what we are left with is to implement the thing ourselves. Which is even more fun, isn't it?<br>Fortunately it sounds like a pretty simple set up. That does add a couple of moving parts to a static blog, though nothing that you can't bolt on top in a day.

So what do we need for the thing to work?

A wallet to receive funds to

A worker to execute the payment processing logic

A resource we want to paywall

I have items 1 and 3, but not 2. In this role for now I will go with Cloudflare Workers, since I host my site there. This also dictates the choice of a language we will implement the thing on, TypeScript. Maybe later I will reimplement it to be hosted on my local server, but to keep the scope of the experiment manageable - let's stick with cloudflare for now.

The middleware

So let's jump right in. The first thing we need is a middleware that will receive the request, and make sure the access is granted only on payment as well as handling the price disclosure.<br>The official docs have an example of how to implement it in Hono, so we'll use that. Making a couple of modifications to accommodate for the fact that the code will run on a cloudflare worker rather than a standalone server, putting our wallets, and replacing the example endpoint with a much more useful one - we get this:

import { Hono } from "hono";<br>import type { MiddlewareHandler } from "hono";<br>import { paymentMiddleware, x402ResourceServer } from "@x402/hono";<br>import { ExactEvmScheme } from "@x402/evm/exact/server";<br>import { ExactSvmScheme } from "@x402/svm/exact/server";<br>import { HTTPFacilitatorClient } from "@x402/core/server";

const app = new Hono();<br>const evmAddress = "0xD040AEACCdFf083C5D4cB221F1533e8719a84F0e";<br>const svmAddress = "HjexCvNzgxJT3Ni7rb98WF4pQGEX2fN7G6Zh26B19mBc";

const facilitatorClient = new HTTPFacilitatorClient({<br>url: "https://x402.org/facilitator",<br>});

let payment: MiddlewareHandler | undefined;

app.use(async (c, next) => {<br>payment ??= paymentMiddleware(<br>"GET /api/joke": {<br>accepts: [<br>scheme: "exact",<br>price: "$0.01",<br>network: "eip155:84532",<br>payTo: evmAddress,<br>},<br>scheme: "exact",<br>price: "$0.01",<br>network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1",<br>payTo: svmAddress,<br>},<br>],<br>description: "A premium, hand-picked joke",<br>mimeType: "application/json",<br>},<br>},<br>new x402ResourceServer(facilitatorClient)<br>.register("eip155:84532", new ExactEvmScheme())<br>.register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme()),<br>);<br>return payment(c, next);<br>});

const jokes = [];

app.get("/api/joke", (c) => {<br>return c.json({<br>joke: jokes[Math.floor(Math.random() * jokes.length)],<br>});<br>});

export default app;<br>The worker also needs a wrangler.jsonc (cloudflare specifics)<br>"name": "x402-poc",<br>"main": "src/index.ts",<br>"compatibility_date": "2026-07-01",<br>"compatibility_flags": ["nodejs_compat"],<br>"env": {<br>"production": {<br>"name": "x402-poc",<br>"routes": [<br>{ "pattern": "shtein.me/api/*", "zone_name": "shtein.me" }<br>Two non-obvious bits in there: nodejs_compat is required because the x402 packages import Node built-ins (events, crypto, url) and the build fails without it. And the route lives only in the production environment on purpose: with a route defined, wrangler dev emulates the route's host, so the URLs the middleware generates would point at the real domain instead of localhost.

Running it locally:

npx wrangler dev<br>And sending a test request - we see the paywall:

curl -i http://localhost:8787/api/joke<br>HTTP/1.1 402 Payment Required<br>Content-Length: 2<br>Content-Type: application/json<br>PAYMENT-REQUIRED:...

x402 payment import cloudflare hono from

Related Articles