In the early 1990s, the HTTP specification reserved a special status code for payments, the “402 Payment Required.” status. The idea? Websites could charge for content directly through the browser. Fast forward 25+ years, and 402 is still sitting there, lonely and unused, just like that gym membership you S-W-O-R-E you’d use.
The reason behind 402 is simple: traditional payment rails are too slow and expensive for small payments. Credit card processing takes days to settle, usually costs 2–3% in fees, and requires users to trust merchants with sensitive payment info. For microtransactions like a $3 code review or even a 1$ virtual “buy me a coffee”, it’s totally impractical.
So we understand that traditional payment rails make micropayments economically impossible due to costs that can end up taking a hefty chunk of your hard-earned dollars. But what if we could make HTTP 402 actually work?
Now I can already hear the crypto bros in the back screaming “CRYPTO! CRYPTO IS THE ANSWER TO ALL YOUR PROBLEMS IN LIFE!” and while that is true for mostly everything, it’s not going to work in our microtransactions case. A bitcoin payment can take a long time (10–60 minutes usually) to get mined, not to mention bitcoin fees are not that small. But Solana…
Solana changes the game completely:
This means that if you charge $0.50 for an article, you will get to keep $0.4999 of it. The user gets instant access — no loading screens, no “processing payment” spinners. Just pay -> verify -> content unlocked!
To help facilitate the use of HTTP 402 and crypto, the wonderful champs over at Coinbase created the x402 protocol, which in Coinbase’s own words is
The x402 protocol sets a standard for implementing the HTTP 402 status code using cryptocurrency payments. The concept is quite elegant: when a server wants payment for content, it responds with 402 status code and includes payment details (recipient address, amount, payment method) in the response headers and payload. The client processes the payment on-chain, then retries the request with cryptographic proof of payment. The server verifies the payment and returns the content. No payment processors, no middlemen, not even a goddamn pigeon moving your money from place to place. Just pure peer-to-peer value transfer.
Now (there’s always a now), while it’s true that the x402 library does provide various implementations and facilitators for different blockchains, its Solana support is still in its infancy, and therefore in this post we are going to implement the HTTP 402 pattern ourselves based on the x402 protocol 🙌.
Implementing the protocol ourselves will allow us to see exactly how 402 works under the hood, and as a bonus, we won’t need to deal with package dependencies, or limit ourselves to a certain supported token.
You should think of x402 as a blueprint, and we’re building a house following its design.
The x402 protocol is built around a simple request-response-retry pattern. Here’s what happens under the hood:
1. Initial Request: A client (user, AI agent, etc.) makes an HTTP request to access a resource.
2. 402 Response: The server responds with HTTP 402 Payment Required and includes payment details in both headers and response body:
HTTP/1.1 402 Payment Required
WWW-Authenticate: Solana realm="api"
x-Payment-Address: 7xK8...q2v
x-Payment-Amount: 0.001
x-Payment-Currency: SOL
x-Content-Type: application/json
{
"error": "payment_required",
"message": "Payment required to access this endpoint",
"payment": {
"address": "7xK8...q2v",
"amount": 0.001,
"currency": "SOL",
"network": "solana-devnet"
}
}
3. Client Processes Payment: The client creates and signs a blockchain transaction transferring the requested amount to the recipient address
4. Transaction Broadcast: The transaction is broadcast to Solana and waits for confirmation
5. Retry with Proof: The client retries the original request, this time including the transaction signature as proof of payment:
POST /api/chat
Content-Type: application/json
Payment-Signature: E37k...x2P
{
"message": "Hello!"
}
6. Server Verification: The server fetches the transaction from the blockchain and verifies that:
7. Content Delivery: If all verification passes, server responds with HTTP 200 OK and the requested content. If not, back to 402!
For us visual bros here’s a nice diagram demonstrating the whole flow:
📣 It’s important to note that while we’re following the 402 pattern that x402 pioneered, our implementation is streamlined:
The beauty of the 402 pattern is that it’s just HTTP — you can implement it however you want, as long as you follow the basic flow.
Enough theory — time to get our hands dirty. We’re going to build a complete HTTP 402 payment system using Solana, for fun and games of course.
So, What Are We Building?
We’re creating a 3-part system that demonstrates HTTP 402 in action:
The flow is simple but powerful: The agent makes a request → API returns 402 → Agent pays autonomously → API verifies payment → Content delivered. No accounts, no credit cards, no payment processors. Just pure peer-to-peer value transfer awesomeness.
Tech Stack
Here’s what we’re working with:
Project Structure
http-402-demo/
├── api/ # Backend API Server
│ ├── src/
│ │ └── index.ts # Main API with 402 logic
│ ├── package.json
│ └── .env.example
│
├── agent/ # Autonomous AI Agent
│ ├── src/
│ │ └── index.ts # Agent that handles 402s
│ ├── package.json
│ └── .env.example
│
└── README.md
Before we dive in, make sure you have:
let’s start by cloning the repo:
git clone https://github.com/jtordgeman/http-402-starter.git
cd http-402-starter
The starter branch has everything scaffolded — we just need to fill in the 402 payment logic as we go. If you get stuck, you can always peek at the finished branch for the complete implementation.
We kick things off with the API server — the ♥️ of our HTTP 402 system!
Building the API Server
Our API has literally one job: guard content behind a paywall that only accepts Solana transactions as payment. Simple and to the point.
First, install dependencies and set up your environment:
cd api
npm install
cp .env.example .env
Open the .env file and fill in your values:
PAYMENT_ADDRESS=<your_solana_wallet_address> # Where payments will go
PAYMENT_AMOUNT=0.001 # Amount in SOL
SOLANA_RPC_URL=https://api.devnet.solana.com # Use devnet for testing
ANTHROPIC_API_KEY=<your_key_here> # Optional, enables real AI responses
Our server is built with Hono — think Express but faster and TypeScript-first. The imports and configuration are already set up for you in the starter project:
https://medium.com/media/d4d8bf28cd625dfed7d0ffdaa47da1f9/hrefSee that createSolanaRpc call? That’s the Solana kit way of connecting to the blockchain. If you’re coming from Web3.js 1.x, this used to look like:
import { Connection } from '@solana/web3.js';
const connection = new Connection('https://api.devnet.solana.com', 'confirmed');
Step 1: Replay Attack Prevention
Our first order of business is to take care of security. Imagine this loophole: someone paid one of our 402 requests and now they are reusing the same transaction signature over and over again. Each Solana signature is unique per transaction, so if we store every signature we’ve seen, we can instantly reject any that’s been used before. Easiest way to do this in TypeScript? A set. Why is it perfect for us?
Add the processedSignatures set right after the service initialization:
const processedSignatures = new Set<string>();
Step 2: Verifying the Payment
This is the most important function in the whole project. When a client claims they paid, we go directly to the Solana blockchain to verify their claim. It’s not that we don’t trust them, it’s just that we don’t trust them :) (also, the blockchain doesn’t lie!)
https://medium.com/media/52febba109d141c39ccc878b3716bf5a/hrefSo what’s going on here?
That’s it for our legendary verify payments method. Let’s move on to the chat route.
legendary indeedStep 3: The chat Endpoint
This is where all the pieces come together, a.k.a the full HTTP 402 awesomeness. The chat route reads like a bouncer at a club: no ticket/bad ticket? no entry. Only once everything checks out do you get in.
Update the /api/chat handler as follows:
https://medium.com/media/1dcbe20bdee7ce9dba994eba76eb108f/hrefLet’s walk through it:
With the main method all laid out, let’s add the support methods:
https://medium.com/media/9da2a63d3745412e0a862c0e27fe5769/hrefSo what do we have here?
Step 4: Test Run
Let’s do a quick test just to verify everything is working smoothly. Start the API server:
npm run dev
Run a quick test to verify the 402 gated endpoint:
curl -X POST http://localhost:3000/api/chat \
-H "Content-Type: application/json" \
-d '{"message": "hello"}'
If all went well you should get back a response similar to this:
{
"error": "payment_required",
"message": "Payment required to access this endpoint",
"payment": {
"address": "YourAddress...",
"amount": 0.001,
"currency": "SOL",
"network": "solana-devnet"
}
Beautiful. Our API is now refusing to work for free 💸. Next, it’s time to build the agent that pays the bills.
Building the Agent 🤖
If we imagined our API as the paywall guard, the agent is that club-goer friend we all have, who knows how to talk their way in (or in our case, pay their way in). The agent’s only job is to make a request, handle the 402 like a champ, and retry with payment proof. Let’s build it.
First, just like before, install dependencies and set up your environment:
cd agent
npm install
cp .env.example .env
Open the .env file and fill in your values:
API_URL=http://localhost:3000 # Your API server
AGENT_WALLET_KEY=your_private_key # Agent's Solana wallet (for autonomous payments)
SOLANA_RPC_URL=https://api.devnet.solana.com
Step 1: Making the Request
This is the heart of the agent, the method that orchestrates the entire 402 flow. It starts by making a normal request, just like any HTTP client would. When we get a 402 back, we parse the body into this shape:
https://medium.com/media/5e8a6e89dd76bf02b6a8f171ec9035b1/hrefThe API already sends all of these properties (easily verifiable, just check the API project response), we’re just giving it a type so TypeScript keeps us honest. Now let’s actually use it. Add the following to your src/index.ts file:
https://medium.com/media/e27c93150f8c54a30d5e68b86124bd21/hrefBefore you ask, yes we use two methods to handle the request: fetchChat is a dead-simple private helper. Its one job is to fire the request and optionally include the Payment-Signature header. makeRequest is the method that owns all the flow:
The 402 flow doesn’t look so scary now does it?
Step 2: Handling the Payment
Now comes the real fun part, we are finally touching those sweet sweet 💸💸! When makeRequest hits a 402, it hands off to handlePayment which takes care of the payment entirely on its own. No user input, no manual signing, no readline prompts.
pure magic indeedFirst, have a look at the constructor of the AIAgent class:
https://medium.com/media/6714d081e40d1c73e1f33fc4eccaadbb/hrefThe constructor wires all the RPC related functionality we need:
Next, add the handlePayment method to the src/index.ts file as follows:
https://medium.com/media/f397978d421a413458e86ad804f3f594/hrefA few things worth calling out:
Step 3: Test Run
Start your API server first (in a separate terminal):
cd api && npm run dev
Then run the agent:
cd agent && npm start
And if everything went well you should see this awesomeness printed out:
════════════════════════════════════════════════════════════
🤖 HTTP 402 Autonomous Agent Demo
════════════════════════════════════════════════════════════
📍 API: http://localhost:3000
🌐 Network: https://api.devnet.solana.com
════════════════════════════════════════════════════════════
✅ Agent wallet loaded
402 response received {
error: 'payment_required',
message: 'Payment required to access this endpoint',
payment: {
address: '5b9r8...KDSM',
amount: 0.001,
currency: 'SOL',
network: 'solana-devnet'
}
}
💰 Paying 0.001 SOL autonomously...
✅ Payment confirmed: 3i5Ak...tX8Qx
Agent response {
success: true,
response: 'Mock AI response to: "Explain HTTP 402 in one sentence"',
payment: {
signature: '3i5Akiq...X8Qx',
verified: true
}
}
✅ Demo completed successfully!
🖐🎤 we finished the whole 402 process, no prompts, no manual steps. The agent detects the 402 response, pays up and retry the request with the proof of payment (signature).
So we built a CLI agent that handles 402s autonomously. But I have a feeling a thought just crossed your mind: what if Claude Code itself could handle HTTP 402 payments natively? Well, that’s exactly what MCP (Model Context Protocol) makes possible.
We already know how to handle payment from our CLI agent, so what will happen if we use the same logic in a MCP tool? 🤔
The 402 MCP Server
The entirety of the MCP server can be found in the /mcp-server/src/index.ts file:
https://medium.com/media/efbd6b31d6839e3dfa156a314848af42/hrefFew things to point out:
Running the MCP server
First, install dependencies and set up your environment:
cd mcp-server
npm install
cp .env.example .env
Make sure you update the .env file with your values:
AGENT_WALLET_KEY=<Your agent wallet private key>
SOLANA_RPC_URL=https://api.devnet.solana.com
For Claude to be able to use the server we must add a .mcp.json file describing the MCP first. When we run claude in our project main folder it will pick up that file and register the MCP for use.
Create a .mcp.json file in the root of the project (same level as agent and api folders) and make sure to update the agent wallet key as well:
{
"mcpServers": {
"http-402-payments": {
"command": "node",
"args": ["./mcp-server/dist/index.js"],
"env": {
"AGENT_WALLET_KEY": "YOUR_BASE58_PRIVATE_KEY",
"SOLANA_RPC_URL": "https://api.devnet.solana.com"
}
}
}
}
Build the server (npm run build inside mcp-server/), then launch Claude Code from your project root.
Seeing it in Action
With the API server running and the MCP server loaded, you can just ask Claude Code naturally:
Claude Code will call make_paid_request, get the 402, pay autonomously, and retry — without you writing any orchestration code. Here's what that looks like:
Look Ma! I can pay on my own!There we go, Claude picked up our MCP and actually paid for its own transaction using 402 🎉🎉🎉
If we look at the bigger picture, HTTP 402 and MCP is a natural fit. MCP tools are how AI agents interact with the world. Payment-gated APIs are how that world charges for access. The two were always going to meet, we’re just doing it a bit early.
HTTP 402 has been sitting in the spec since the early 1990s. The reason it never took off is that the payment layer was always the hard part — credit cards have friction, subscriptions need accounts, micropayments had no good infrastructure. Solana changes that. And AI agents make it worth building, they don’t need onboarding flows, they don’t forget to cancel subscriptions, they just need to pay for what they use, automatically, in the moment they need it.
In this post we demonstrated a payment-gated API, an agent that handles the flow end-to-end, and an MCP server that gives Claude Code the same ability with zero orchestration code.
There’s still more to explore of course. The code in this post is nowhere near production grade, and we didn’t even touch on the web frontend side as wiring 402 into a React app with wallets like Phantom or Solflare is a whole different flow. If you’d like to see a follow-up post on that, let me know in the comments.
HTTP 402 Died in the 90s. Solana Just Brought It Back. was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.


