Payment happened.
Intent stayed private.
px402 is an HTTP payment layer for AI agents. It settles USDC through MagicBlock’s private rail so the public chain records payment without revealing which API received it.
- sender
- 3wBh...AiA
- mint
- USDC
- amount
- 0.01
- recipient
- [ REDACTED ]
- api route
- [ REDACTED ]
- revenue map
- [ REDACTED ]
Settlement remains real. The link between payer intent and API recipient does not reach the public chain.
The chain sees settlement. Not intent.
An outside observer can prove USDC moved. They cannot connect that payment to the API, recipient wallet, or server revenue map.
- 01Sender wallet
- 02Mint (USDC)
- 03Amount (micro-USDC)
- 01[ RECIPIENT WALLET REDACTED ]
- 02[ WHICH API WAS PAID REDACTED ]
- 03[ SERVER'S REVENUE MAPPING REDACTED ]
One request. Six verifiable steps.
px402 keeps the familiar HTTP payment loop. The private rail changes what settlement exposes, not how the client handles a 402.
- 01
Request
Agent asks the protected API for data.
GET /data - 02
Challenge
Server returns price, destination token, and expiry.
402 - 03
Settle
Client signs a USDC transfer through MagicBlock.
private rail - 04
Redact
The TEE resolves the recipient away from public view.
TEE - 05
Verify
Subscriber matches the settlement by clientRefId.
base chain - 06
Respond
The same request retries and receives the paid result.
200 OK
Open the full protocol sequence

Choose a side. Add one package.
API providers add a framework adapter. Agents replace fetch. MCP users run the server directly. Production configuration stays explicit and out of the landing-page happy path.
import { Hono } from "hono";import { px402 } from "@px402/hono"; const app = new Hono();app.use(px402(paymentConfig));app.get("/api/sentiment", handler);pnpm add @px402/hono @px402/core
import express from "express";import { px402 } from "@px402/express"; const app = express();app.use(px402(paymentConfig));app.get("/api/sentiment", handler);pnpm add @px402/express @px402/core
// app/api/sentiment/route.tsimport { NextResponse } from "next/server";import { withPx402 } from "@px402/next"; export const GET = withPx402( paymentConfig, () => NextResponse.json({ signal: "bullish" }),);pnpm add @px402/next @px402/core
import { Px402Client } from "@px402/client"; const client = new Px402Client({ wallet, mint });const res = await client.fetch("https://api.px402.allensaji.dev/api/sentiment?token=SOL");const data = await res.json();A 402 you can inspect.
The API data is illustrative. The payment path is not. Each route returns a real 402, settles USDC, and serves data only after the retry.
$ curl -i https://api.px402.allensaji.dev/api/sentiment?token=SOL HTTP/1.1 402 Payment Required X-Payment-Amount: 10000 X-Payment-Token: v1.eyJ...
Install only what your role needs.
The protocol stays modular. Providers choose one framework adapter. Agent builders use the client or MCP server. Core carries the shared verification machinery.
Know the boundary before you ship.
px402 narrows what a public observer can link. It does not make the transfer disappear, remove the TEE trust assumption, or turn devnet software into production infrastructure.
- 01Sender wallet
- 02USDC mint
- 03Per-call amount
- 01Recipient wallet
- 02API route
- 03Revenue mapping
- 01MagicBlock TEE
- 02Validator execution
- 03Subscriber configuration
Per-call amount is on-chain.
If only one server charges 0.073 USDC for one specific endpoint, the amount itself is a fingerprint.
Anonymity-set size matters.
At launch, you are alone on the validator. Privacy comes online with volume.
Not a drop-in x402 facilitator.
Migrating from canonical x402-svm is a rewrite, not a config swap.
Pre-alpha. Devnet only.
~4s single-call latency. 96.7% success at 30 concurrent. Numbers from a clean devnet run.
TEE trust assumption.
MagicBlock's TEE has the recipient mapping. If the TEE is compromised, unlinkability is revealed retroactively.
These are current constraints, not hidden footnotes. Read the README for the full list.