@payperbyte/x402-middleware
v0.1.0
Published
Drop-in x402 Trust Middleware — front any data endpoint with USDC pay-per-call, an EIP-712 verify-before-act receipt (X-BYTE-Attestation), and delivery telemetry. Generalizes the PayPerByte x402 gateway. No new contracts.
Downloads
133
Maintainers
Readme
@payperbyte/x402-middleware
Drop-in Foreseal Gate. Put it in front of any data endpoint and instantly get:
- USDC pay-per-call over x402 — unpaid request → HTTP 402 challenge; on payment, proxy upstream and return the bytes.
- A verify-before-act receipt — an EIP-712
PayloadAttestationover the exact bytes served, emitted as theX-BYTE-Attestationheader. A buyer recomputes the hash and recovers the signer before acting. - Delivery telemetry — latency / status / bytes / uptime per call.
- Optional discovery — a Bazaar discovery-extension + manifest entry so the wrapped endpoint surfaces in the x402 ecosystem under your name.
It generalizes the production PayPerByte x402 gateway. No new contracts. The receipt it emits is verifiable by the existing PayPerByte verifiers (the MCP server's verify, the SDK's verify, and the on-chain DataStreamLib) — same BYTE Library EIP-712 PayloadAttestation format.
Phase 1 scope. This is the telemetry pipe + a basic uptime/latency score. A calibrated quality SLA is gated on DQI and is not advertised here. There is no escrow, no staking/slashing, no on-chain fee splitter — those are out of scope by design.
Install
npm i @payperbyte/x402-middleware expressQuick start (Express)
import express from "express";
import { trustMiddleware } from "@payperbyte/x402-middleware";
const app = express();
app.use(express.json()); // required for POST upstreams
app.use(
"/quote",
trustMiddleware({
upstream: "https://my-api.internal/quote", // your real endpoint
price: { perCallUsdc: "0.01" }, // or { perKBUsdc, floorUsdc }
payTo: "0xYourUSDCAddress", // x402 settles here (Base mainnet)
// attestation defaults to 'delivery' — needs X402_MIDDLEWARE_ATTESTATION_KEY
}),
);
app.listen(3000);Set the delivery attester key in the environment:
export X402_MIDDLEWARE_ATTESTATION_KEY=0x<32-byte-hex>That's it. GET /quote now returns 402 until paid, proxies your upstream on payment, and stamps every paid 200 with X-BYTE-Attestation.
Config (TrustMiddlewareConfig)
interface TrustMiddlewareConfig {
upstream: string; // your real endpoint
price: { perCallUsdc: string }
| { perKBUsdc: string; floorUsdc: string };
payTo: Hex; // YOUR USDC address (Base mainnet)
network?: "base" | string; // default eip155:8453
facilitatorUrl?: string; // default discoverable facilitator
attestation?: "delivery" | "provenance" | "off"; // default "delivery"
providerSigner?: Signer; // required iff attestation === "provenance"
discovery?: { list: boolean; name: string; description: string; category: string };
schema?: object; // optional JSON Schema; fail-closed on drift
// ...plus attestationKey, usdcAddress, telemetrySink, method, etc. (see types)
}The two receipt tiers — and why the distinction matters
| Tier | Who signs | What it proves |
|---|---|---|
| delivery-integrity (default) | the PayPerByte middleware attester key | "PayPerByte delivered exactly these bytes at time T, tamper-evident in transit." The recovered signer is the PPB attester. |
| provenance (opt-in) | your key (providerSigner) | "This provider vouches these bytes are theirs." The recovered signer is you. |
We can't attest to the provenance of data we didn't produce — so delivery-integrity is sold as exactly what it is (a signed, timestamped receipt of what was served, tamper-evident). Bring your own key for the stronger provenance claim. Never market delivery-integrity as provenance.
import { privateKeyToAccount } from "viem/accounts";
trustMiddleware({
upstream,
price: { perCallUsdc: "0.05" },
payTo,
attestation: "provenance",
providerSigner: privateKeyToAccount("0x<your-key>"), // satisfies Signer structurally
});How a buyer verifies a receipt
The buyer reads the X-BYTE-Attestation header, recomputes keccak256(body), and recovers the EIP-712 signer — then asserts the signer is the attester they trust:
import { verifyReceipt, parseReceiptHeader } from "@payperbyte/x402-middleware";
const res = await fetch(url, { /* with x402 payment */ });
const body = await res.text();
const receipt = parseReceiptHeader(res.headers.get("x-byte-attestation")!);
const verdict = await verifyReceipt(body, receipt);
if (!verdict.verified) throw new Error(`do not act: ${verdict.reason}`);
// leg 3: assert the signer is who you expect (from the discovery manifest)
if (verdict.recoveredSigner!.toLowerCase() !== EXPECTED_ATTESTER.toLowerCase()) {
throw new Error("unexpected signer — do not act");
}
// safe to act on `body`This is the same two-leg check the deployed PayPerByte verifiers perform (keccak256(body) === payloadHash and recoverTypedDataAddress(...) === publisher), against the consensus-critical BYTE Library EIP-712 domain — so any existing PayPerByte verifier checks this receipt identically.
Fail-closed by design
- Facilitator unreachable → 503. Paid routes fail closed and are never served free while the x402 facilitator is down. The middleware retries the facilitator handshake in the background; until it's ready, every paid request gets a 503.
- Upstream error or schema violation → 502, no receipt. A paid buyer gets an honest error, never a signed payload that violates the advertised
schema.
Telemetry & score
const handler = trustMiddleware({ /* ... */ });
app.use("/quote", handler);
// basic uptime/latency read-back (default in-memory sink)
const score = handler.getScore();
// { calls, okCalls, uptime, p50LatencyMs, p95LatencyMs, totalBytes, note }Point telemetrySink at your own store (Postgres, the PPB indexer) to feed PQS/DQI. The score's note always states it is uncalibrated delivery telemetry, not a quality SLA.
Discovery
const handler = trustMiddleware({
upstream, price: { perCallUsdc: "0.01" }, payTo,
discovery: { list: true, name: "Acme Quotes", description: "Real-time quotes", category: "financial" },
});
// serve a well-known manifest entry for x402 indexers
app.get("/.well-known/x402.json", (_req, res) => {
res.json({ x402Version: 1, resources: [handler.manifestEntry("https://acme.example/quote")] });
});Framework-agnostic core
Non-Express hosts can use the core directly: instantiate TrustEngine, gate it behind any x402 payment check, and call engine.fulfill() once payment is verified.
import { TrustEngine } from "@payperbyte/x402-middleware/core";License
MIT © BYTEDev Inc.
