The micropayment revolution is underway

Payment is just another layer.

x402 is an open protocol that lets an HTTP request pay for itself — a few cents of USDC, settled in seconds, no account on either side. Crosshatch brings it to Effect: pay as a layer, charge as a route.

$ pnpm add crosshatch

x402 v2 TypeScript Apache-2.0

one paid request · x402 v2
POST /v1/reports your code — ordinary HTTP
402 Payment Required the price: 0.01 USDC
POST /v1/reportscrosshatch the payment: signed by your wallet
200 OK settled ✓ — plus the resource

Your program sees one request that succeeds — Crosshatch handles the middle. Step through it →

New to x402?

One paid request, step by step

The whole protocol is those four wire moves. Click through what each one carries — real x402 v2 headers, decoded.

one paid request · x402 v2 1/4

Step 1 · Client — your code

An ordinary HTTP call. No account, no key — the client knows nothing about this API yet.

POST /v1/reports HTTP/1.1
host: api.example.com
accept: application/json
content-type: application/json

{ "topic": "eurusd-volatility" }

// no auth header, no api key —
// the server will answer with a price.

you write: client.execute(HttpClientRequest.post("/v1/reports"))

Step 2 · Merchant — Http402.require

Instead of a body, the response carries terms — what this costs and how to pay. Decoded from the payment-required header:

{
  "x402Version": 2,
  "resource": { "description": "One market report" },
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "asset": "0x8335…2913",
    "amount": "10000",  // $0.01 — USDC has 6 decimals
    "payTo": "0x1c7d…9a42",
    "maxTimeoutSeconds": 300
  }]
}

the merchant wrote: yield* Http402.require({ required })

Step 3 · Client — Http402.layerClient

Crosshatch picks an option it can satisfy, signs a transfer authorization, and retries — your program is still awaiting its first response. Decoded from the payment-signature header:

{
  "x402Version": 2,
  "accepted": { "scheme": "exact", "network": "eip155:8453",  },
  "payload": {
    "signature": "0x74f9…01b3",
    "authorization": {
      "from": "0x9e04…77c1",  // client wallet → merchant
      "to": "0x1c7d…9a42",
      "value": "10000", "nonce": "0x3fb2…c4d8"
    }
  }
}

handled by Http402.layerClient + your Payer

Step 4 · Merchant — Facilitator.settle

A facilitator verifies and settles — money moves now, not at month-end. The response is the resource, plus a receipt in payment-response:

{
  "success": true,
  "transaction": "0xa9c1…e77b",  // settlement receipt
  "network": "eip155:8453",
  "payer": "0x9e04…77c1"
}

// …plus the body your program asked for:
{ "report": "…" }

the merchant wrote: yield* Facilitator.settle({ payload })

Merchant · charge

From free to paid in one flip

402 Payment Required has been in the HTTP spec since 1997, waiting for money that moves at the speed of a request. USDC ended the wait — settlement in seconds, fees in fractions of a cent — just as software learned to spend money of its own. Here’s an ordinary Effect route: flip the switch.

+13 lines
route.ts free
+import { Facilitator, Http402, KnownAssets, Payload, Required, Requirements } from "crosshatch" import { Effect } from "effect"
 import { HttpServerResponse } from "effect/unstable/http"

 export const route = Effect.gen(function* () {+  const payload = yield* Payload.Payload+  if (!payload) {+    const required = yield* Required.make`One market report`.pipe(+      Required.accept(Requirements.logical(KnownAssets.Usd.USDC, {+        amount: 0.01,+        recipients: { eip155: { 8453: payTo } },+      })),+    )+    return yield* Http402.require({ required })+  }+  const settlement = yield* Facilitator.settle({ payload })   const report = yield* Reports.generate()
   return HttpServerResponse.json(report)+    .pipe(Http402.addResponseHeader(settlement)) })

The green lines are the entire diff. Merchant quickstart →

What you’d otherwise be building
  • API keys
  • plan tiers
  • usage metering
  • invoices
  • failed-payment emails
  • webhook reconciliation

What’s left is a price on the route.

Prices no card can move Charge $0.002 for one call — no minimums, no monthly commitment, no free-tier gymnastics.
Agents as customers An agent can discover your API and pay for it mid-task — no human in the loop, no signup form. Services and scripts pay the same way.
A paywall in an afternoon One route handler: price, settle, serve. Everything else about your API stays as it is.

Client · pay

Paying is one layer

Provide Http402.layerClient and 402s are paid and retried inside the client. Highlighted lines are Crosshatch; the rest is ordinary Effect.

An LLM call, bought with USDC instead of an API key

No signup anywhere in this program — exactly what an agent needs to buy data, tools, or model calls mid-task. The same composition works for any paid HTTP resource.

Client quickstart →
pay.ts auto-pay on 402
import { OpenAiClient, OpenAiLanguageModel } from "@effect/ai-openai-compat"
import { Http402 } from "crosshatch"
import { Effect, Layer } from "effect"
import { LanguageModel } from "effect/unstable/ai"
import { PayerLive } from "./payer" // wallet + signing (see quickstart)

// Any x402-priced API. No account. No key.
const Blockrun = OpenAiLanguageModel.layer({
  model: "deepseek/deepseek-chat",
}).pipe(
  Layer.provide(OpenAiClient.layer({ apiUrl: "https://blockrun.ai/api/v1" })),
)

LanguageModel.generateText({
  prompt: "Hello from Crosshatch.",
}).pipe(
  Effect.provide(Blockrun.pipe(
    Layer.provide(Http402.layerClient.pipe(Layer.provide(PayerLive))),
  )),
  Effect.runFork,
)

Why Crosshatch

The protocol is simple. The details aren’t.

The demos are short because the machinery lives down here — x402 v2, end to end.

Requirements.logical(USDC, { amount: 0.01 })
  • token addresses
  • decimals
  • signing domains

for every supported network — EVM and Solana alike.

yield* Payload.Payload
  • header decoding
  • schema validation
  • typed failures

every x402 v2 message and CAIP identifier — malformed payments die at the boundary.

Http402.require({ required })
  • base64 headers
  • response shapes
  • versioning

the v2 wire format, down to the 402 itself.

Facilitator.settle({ payload })
  • signature checks
  • replay protection
  • on-chain settlement

through a hosted facilitator, or your own — same toolkit.

Http402.layerClient
  • 402 interception
  • option selection
  • signing
  • retry

one Layer — typed errors, tracing, and structured concurrency throughout.

crosshatch profile add
  • key generation
  • keychain encryption
  • funding

a dev wallet in one command.

And it meets Effect where it already is: HttpClient, server middleware, Effect RPC — streaming payments per message — Effect AI, and effect-atom.

FAQ

Is this crypto? Do I need to care about blockchains?

There’s no token and nothing to speculate on. x402 settles in stablecoins like USDC — tokens that hold a steady $1 — the only rail that can move half a cent, machine to machine, in seconds. You price in dollars; for most apps the entire crypto surface is KnownAssets.Usd.USDC and an amount.

Why not just use Stripe?

Different regime. Card rails cost ~30¢ before your price starts, and every buyer must be a human with a card and a signup. x402 is for the other case: prices in cents or fractions of one, and buyers that are often programs. Selling $29/month to people? Keep Stripe. Selling $0.01 requests to anyone — or anything? That’s x402.

Doesn’t paying per request make everything slow?

The 402 exchange adds one round trip before the first paid response. Verifying a payment is a signature check, not a blockchain wait — and delivery is your call per route: serve immediately and settle in the background, or hold until settlement confirms, which lands in seconds.

What about refunds and disputes?

A settled payment is final — like cash, there’s no chargeback machinery in the protocol. At per-request prices that’s a feature: the blast radius of a bad call is a cent, not an invoice cycle. Refunding is just another transfer if you choose to make one; no third party can force it either way.

Where does the money actually live?

Clients pay from a wallet — a keypair holding USDC, not an account with a provider (crosshatch profile add makes one for development). Merchants receive at the address on the requirement: yours on settlement, in seconds, no payout schedule.

Is x402 real? Who’s behind it?

An open protocol with an open spec, started at Coinbase, adopted by a growing ecosystem of paid APIs and agent platforms. Crosshatch implements v2 and is Apache-2.0 — the protocol is data; there’s no lock-in.

Get started

Pick a side. Or both.

Buying

Pay for x402 resources

Set up a payer, wire the client layer, and consume paid APIs from any Effect program — or hand your agent a wallet.

Client quickstart
Selling

Charge for your routes

Declare a price, return 402 until paid, settle, and serve — in one route handler.

Merchant quickstart

Building with a coding agent? Point it at crosshatch.dev/llms-full.txt — the full docs as one file.