Hanzo

x402

Package x402 is pay-per-request over HTTP 402: quote a price, take the payment, serve the resource.

Package x402 is pay-per-request over HTTP 402: quote a price, take the payment, serve the resource.

Base URLhttps://api.hanzo.ai
Operations1
AuthAuthorization: Bearer $HANZO_API_KEY

Specification

HIP-1163 · x402 — Pay Per Request — Draft · read the specification →

x402 is pay-per-request over HTTP 402: quote a price, take the payment, serve the resource. It speaks x402 protocol version 2 — challenge, EIP-3009 transferWithAuthorization signed over the advertised terms, verify, settle exactly once, serve — native to the cloud binary. It is a rail and nothing else: the marketplace declares what is priced and who is paid, wallets says where the money lands, and this capability enforces. The implementation is hanzoai/cloud apps/x402.

Motivation

A marketplace where agents buy tools and data per call needs a payment that works without an account relationship: the buyer may be a client that has never heard of the seller, and the price may be a fraction of a cent. HTTP 402 with a signed transfer authorization is the shape that fits — the challenge carries the terms, the retry carries the proof, and no session, invoice or card vault sits between them. What it demands in exchange is exactness: replay, double-settlement and misdirected credit are all one-request attacks if the rail is loose anywhere.

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 The wire is the spec's, not ours

The protocol is x402 version 2 as specified by x402-foundation/x402 (specs/x402-specification-v2.md and its HTTP transport binding). Every field name, header name and error reason on the wire MUST be the one the specification prints (apps/x402/protocol.go): the wire is a contract with other people's clients, and a client that has never heard of Hanzo must be able to pay us. The version is a number on the wire (x402Version: 2) and the only thing that decides how a message is read — a wire whose shape depends on an operator flag is two wires. One scheme (exact), one transfer method (EIP-3009); signature verification is secp256k1 recovery over the EIP-712 domain the challenge itself stated. The default settlement network is eip155:36963, the Hanzo L1, matching wallets.

§2 The store, and settle-once

One SQLite store, x402 (apps/x402/store.go:55): one row per claimed authorization, keyed by a deterministic id derived from (payer address, nonce). That id is both the replay-dedup key — a primary key, so a second insert of the same authorization is atomically refused — and the idempotency ref on both money writes, so the fast in-pod dedup and the ledger's own idempotency agree on one key. A row is written at claim and flipped at settle; an interrupted settlement is recoverable because the claim names payer, payee, amount and the payee's ledger subject, and startup Reconcile completes anything the last process left in doubt (apps/x402/x402.go:181). The payee subject is on the row and MUST NOT be re-resolved at completion time — a claim has to be sufficient on its own, or the sweep silently pays whatever the wallet resolves to later.

§3 The address, and the three callers

The addressed surface is one typed operation, GET /v1/x402/settlements/{id} (manifest/apps.go:174) — the receipt lookup, scoped by principal.Ledger, which folds in the SuperAdmin masquerade so an admin inspecting another org still reads their own settlements (apps/x402/x402.go:791). The flow itself is written once (run) and reached three ways: Enforce, a handler a priced route group applies; Settle, the same flow for a resource named in a request body; and the plane op /x402/settle for the fleet's one-binary-per-app shape, where the payer is the caller's org resolved at the edge and never a field (apps/x402/rpc.go). On the plane the outcome is data, not a transport error — a 402 carries the terms the client must read to pay — so a transport error means the rail did not answer, and callers fail closed on it, never free.

§4 Money

The surface declares cloud.Free (plugin/x402/main.go): the rail itself charges nothing per request. The money it moves is the settlement — a payer debit through the metering spine under provider label x402 with the settlement id as Ref (apps/x402/x402.go:732), which is how paid usage appears in billing/usage like any metered spend, and a payee credit deposited into the ledger subject of the wallet the publisher's listing named, resolved through wallets (HIP-1161). What a resource costs is the marketplace registry's table; when the price cannot be learned the answer MUST be an error, never "free" — a rail that reads its own outage as "nothing is priced" sells the whole catalogue for nothing (apps/x402/peer.go). Unknown payee is 503; unreachable ledger is no settlement, no receipt, no dispatch.

§5 Events and telemetry

It publishes nothing on the bus; a customer's webhooks receive no x402.* events. Beyond the request span, each settlement appends an audit record (resource type x402.settlement, redacted; apps/x402/x402.go:899), and the startup reconcile logs what it completed.

§6 Upstream

It implements the x402 specification version 2 (x402-foundation/x402) — a wire specification, not a code fork; no upstream implementation is embedded. Signature recovery rides github.com/luxfi/crypto v1.20.5 (Lux Ecosystem License 1.2), the same primitive wallets custody signs with. Persistence is github.com/hanzoai/sqlite (MIT / Apache-2.0 dual).

§7 Stage

beta: the manifest row declares it (manifest/apps.go:174, Stage: Beta; HIP-0139 §8), reached by flag until promoted.

Rationale

The alternative to a rail-plus-registry seam is a payments module inside each priced subsystem. That is N copies of verify-and-settle, N nonce stores that do not share a dedup key, and a marketplace that cannot price a resource without shipping code into its owner. One rail, inert until a registry is published, keeps enforcement in one place and pricing where the catalogue is.

Security Considerations

The attacks are the classic payment ones, and each is closed structurally. Replay: the (payer, nonce) primary key refuses a second claim atomically, and the same id is the ledger's idempotency key, so even a bug in the fast path cannot double-move money. Redirection: the payee org comes off the listing row and the payer off the edge-resolved principal — neither is a request field, so a buyer can neither choose who is paid nor who pays. Free-fall: the priced set must fail closed (§4); the one exception this rail ever held — reading an unreachable marketplace as "no marketplace, nothing priced" — is recorded in apps/x402/peer.go as the defect that sold everything for nothing, and is why the price has no exception now.

Four surfaces

SurfaceReaches this capability asCoverage
RESTx402 at its own prefix1 operation
CLIhanzo x402 …1 of 1
SDKX402Api in every published client1 method
MCPtool x402 on https://api.hanzo.ai/v1/mcp1 operation, 0 under the document's own id — ask describe for the rest

Quickstart

export HANZO_API_KEY=sk-...   # console.hanzo.ai → API keys

Then the first call. This one takes arguments — the placeholders are yours to fill. GET /v1/x402/settlements/{id}, operation get_x402_settlements_by_id:

hanzo x402 settlements get <id>

Answers 200 with object — ok.

Endpoints

EndpointWhat it does
GET /v1/x402/settlements/{id}Settlement reads one x402 payment receipt by id.

All Hanzo APIs · Interactive reference

How is this guide?

On this page