x402 adapter
The @quitanza/x402 adapter maps the HTTP 402 payment-required handshake onto the Quitanza escrow lifecycle, so an x402-style paid request settles with recourse and ends in a quitanza instead of a bare transfer. The adapter is live today on simulated rails (scheme quitanza-sandbox, network quitanza-local); integration with external x402 facilitators is in development.
The handshake, settled through escrow
- The client requests a paid resource. The server answers
402 Payment Requiredwith anacceptsarray of payment requirements: price, asset, resource id, and the server's Ed25519 key aspayTo. - The client builds a payment authorization, a signature over canonical
{amount, asset, from, payTo, resource}, and retries with it base64-encoded in theX-PAYMENTheader. - The server verifies the authorization, runs a full escrow lifecycle for the request (create → fund → deliver the resource → verify → settle), and responds with the resource plus an
X-PAYMENT-RESPONSEheader naming the escrow and the quitanza that proves the matter closed.
Every step lands on the escrow's hash-chained evidence trail, exactly as in a long-form escrow.
Try it against the sandbox
The local API serves a live demo resource:
GET /v1/x402/demo
→ 402 { "x402Version": 1, "accepts": [ { "scheme": "quitanza-sandbox", "maxAmountRequired": "0.10", … } ], "error": "…" }
Client side, with the adapter:
import { createPaymentHeader } from "@quitanza/x402";
import { generateKeypair } from "@quitanza/core";
const payer = generateKeypair();
const offer = (await (await fetch(url)).json()).accepts[0];
const paid = await fetch(url, {
headers: { "X-PAYMENT": createPaymentHeader(offer, payer) }
});
// paid.headers.get("X-PAYMENT-RESPONSE") names the quitanza.
Server side, X402Gateway wraps any resource:
import { X402Gateway } from "@quitanza/x402";
const gateway = new X402Gateway({ engine, payTo: serverKeys });
const requirements = gateway.requirements({
resource: "/reports/q2",
amount: "0.10",
asset: "USDC",
description: "Q2 report"
});
// no X-PAYMENT header → respond 402 with gateway.paymentRequired(requirements)
// valid header → gateway.settle(header, requirements, resource) returns
// { escrow, delivery, verdict, quitanza, responseHeader }
Why escrow under 402
A bare 402 payment is fire-and-forget: the client pays, and what arrives is whatever arrives. Routed through Quitanza, the same handshake gains verification against terms, a dispute path, timeout guarantees, and a terminal proof either party can hold.
Status
| Piece | State |
|---|---|
| 402 handshake, X-PAYMENT / X-PAYMENT-RESPONSE headers | Live |
| Escrow lifecycle per paid request, quitanza issued | Live |
| Rails | Simulated (quitanza-local): no chain, no real funds |
| External facilitator integration | In development |