Skip to content
Tenzro
Documentation menu
Payments

x402

Pay for any HTTP resource on Tenzro with the open x402 protocol: exact, metered and batched schemes, verified by the node's own facilitator.

x402 is an open protocol that puts payment inside HTTP. A server answers a request with 402 Payment Required and a description of what to pay; the client signs a payment and retries; the server verifies, settles and serves. On Tenzro Network, every paid route on a node speaks x402, including the OpenAI-compatible inference APIs, storage, databases and hosted sites.

Every Tenzro node runs its own x402 facilitator. Verification and settlement happen on the node that serves the request, against the Tenzro ledger, with no third party in the path.

How a payment works

  1. The client calls a paid resource without a credential.
  2. The node returns 402 with one or more payment requirements: scheme, network, asset, payee (payTo), maximum amount and a validity window.
  3. The client picks a requirement, signs a payment payload with the paying account's key and retries the request with it.
  4. The node verifies the payload, settles it on the ledger and serves the response with a receipt.

The requirement is bound to the resource, payee and amount it was issued for, and the debited account is always the one whose key signed the payload. A receipt is returned once the settlement transaction is in a finalised block.

Schemes

A requirement names its scheme, and the node dispatches to the matching verifier. Each scheme signs a domain-separated preimage, so an authorisation for one scheme can never be replayed as another.

SchemeUse it forHow it settles
tenzro-hybridDefault for payments in TNZOSigned with a hybrid classical and ML-DSA-65 signature; settles as a ledger transaction
exact-eip3009A fixed amount in a stablecoin that supports EIP-3009The node's facilitator verifies and submits the transfer authorisation
permit2A fixed amount in any ERC-20 through Permit2Verified and submitted by the node's facilitator
erc7710Payment redeemed from a delegationVerified against the delegation's caveats
uptoMetered work where the price is known only after servingThe buyer signs a ceiling; the provider captures the metered amount up to it
batch-settlementStreams of small chargesThe buyer deposits once and signs cumulative vouchers; the provider settles the latest voucher in one transaction

The schemes a resource accepts are listed in its PAYMENT-REQUIRED header. The rails a payment can settle on, and the smallest worthwhile payment on each, come from the open method tenzro_settlementNetworks.

Metered payments with upto

An inference or query endpoint rarely knows the cost before it runs. With upto, the buyer authorises a maximum once. The provider serves the request, meters what was used, for example tokens generated, and captures that amount against a usage record from the serving node. The capture can never exceed the signed ceiling. Metered, per-use settlement is the default for Machine Economy services. See SLA attestation and metering.

Batch settlement

For per-token billing or per-epoch storage, settling every charge on-chain is wasteful. With batch-settlement, the buyer deposits into a channel and signs a cumulative voucher for each charge. Each voucher commits to the channel and the running total, so the provider only needs the latest one. At close, the provider redeems it against the deposit in a single transaction and the remainder returns to the buyer.

Facilitation

A node does not expose a facilitator API of its own. It verifies tenzro-hybrid payments itself. For the EIP-3009 and Permit2 stablecoin schemes, the node's operator configures facilitation in the node's config file, in the [payments.x402_facilitator] table:

toml
[payments.x402_facilitator]
evm_rpc_url = "https://<evm-json-rpc-endpoint>"
chain_id = 84532
# Broadcast settlements through an external x402 facilitator:
settlement_facilitator_url = "https://<x402-facilitator>"

# Or broadcast them with the operator's own relayer key on a hardware device:
# [payments.x402_facilitator.relayer_signer]
# device_kind = "ledger"            # ledger, trezor or gridplus
# derivation_path = "m/44'/60'/0'/0/0"

The node runs the admission checks itself against evm_rpc_url before anything is submitted: network, payee and amount match the requirement; the signed time window is current; the signature recovers to the payer; the nonce is unused; the payer holds the funds; and the transfer simulates successfully. The transfer is then broadcast by the relayer when relayer_signer is set, or by the facilitator at settlement_facilitator_url otherwise, and the node confirms on evm_rpc_url that it executed. Without this table the node offers no EIP-3009 or Permit2 scheme.

Payments that A2A tasks ask for are settled by the facilitator at payments.facilitator_url (the node calls POST {url}/settle). Without one, an A2A task that needs a payment cannot be paid on that node.

Stablecoin payments over x402 are covered in Stablecoin payments.

Paying a resource

From TypeScript, with npm install tenzro-sdk (and @tenzro/device-key for the hardware key), web.payingFetch answers a 402 by signing one of the offered requirements with the paying account's key and retrying, never paying more than the ceiling:

ts
import { HardwareKeySigner, openHardwareSigner, web } from "tenzro-sdk";

const signer = openHardwareSigner({ label: "tenzro/wallet" });
if (!(signer instanceof HardwareKeySigner)) throw new Error("no TPM or Secure Enclave on this machine");

const pay = web.payingFetch(new web.HybridPayer(signer, "did:tenzro:human:<you>"), { maxAmount: 100_000n });
const res = await pay("https://api.example.com/forecast");
console.log(res.status, await res.text());

web.HybridPayer pays tenzro-hybrid requirements. A delegated agent pays batch-settlement requirements from its channel with web.AgentChannelPayer, whose vouchers its serving node signs within the agent's Terms.

To answer a challenge a node issued (tenzro_createPaymentChallenge with protocol x402), sign a credential for it on the paying device and hand it to the payee, who checks it with tenzro_verifyPayment:

ts
import { TenzroClient, type PaymentChallenge } from "tenzro-sdk";

const client = new TenzroClient({ endpoint: "https://rpc.tenzro.com" });

// The challenge from the resource's 402 answer, or one a payee created with
// client.payment.createChallenge(resource, amount, asset, "x402").
declare const challenge: PaymentChallenge;
const credential = await web.signChallengeCredential(challenge, signer, "did:tenzro:human:<you>", 100_000n);
const check = await client.payment.verifyPayment({ credential });
console.log(check);

From the CLI, the payee issues the challenge and verifies the credential it receives:

bash
tenzro payment challenge /v1/chat/completions --amount 100000 --protocol x402 \
  --recipient <payee-address> --rpc https://rpc.tenzro.com > challenge.json
tenzro payment verify --credential "$(cat credential.json)" --rpc https://rpc.tenzro.com

Paying is an owner action: the credential must be signed by the paying account, and an agent's delegation scope and spending limits apply. See Payments.

Selling a resource

A seller answers an unpaid request with 402 Payment Required and its payment requirements in the PAYMENT-REQUIRED header: the scheme, network, asset, payee and amount it accepts. The buyer retries with its payment in the PAYMENT-SIGNATURE header, and the seller serves once a facilitator has settled it. With the TypeScript SDK, web.PublisherGate does this for a set of paid routes:

ts
const gate = new web.PublisherGate({
  policy: {
    chainId: 133801,
    payTo: "0x<your-account>",
    facilitator: "https://<x402-facilitator>",
    routes: [{ path: "/forecast", usdE6: 10_000 }],
  },
  quote: async (usdE6) => (await client.payment.quote(usdE6)).amount,
});

export default {
  fetch: (request: Request) => gate.handle(request, async () => new Response("forecast")),
};

A route priced in USD is quoted in TNZO at the consensus rate (tenzro_quotePayment). Each settled payment is a consensus record the seller can read back with tenzro_getPayment or list with tenzro_listPayments.

ExploreJoin the network