Three packages, and a working metered service in about forty lines. One implements the x402 upto scheme on Hedera; one makes its receipts verifiable by anyone; one hands both to an AI agent.
Add both packages alongside their peers. @x402/core and @hiero-ledger/sdk are peer dependencies you already have if you run an x402 service on Hedera.
npm i x402-hedera-upto x402-hedera-receipts @x402/core @hiero-ledger/sdkRequires a facilitator that supports upto on Hedera. No public one does yet — run your own (§04), which x402 encourages and Hedera’s docs ask for.
The buyer registers the scheme and lets @x402/core answer 402s automatically. Paying costs one off-chain EIP-712 signature — no transaction, no gas, no HBAR.
import { x402Client } from '@x402/core/client';
import { createUptoClientSigner } from 'x402-hedera-upto';
import { UptoHederaScheme } from 'x402-hedera-upto/upto/client';
import { PrivateKey } from '@hiero-ledger/sdk';
const signer = createUptoClientSigner(
'0.0.BUYER',
PrivateKey.fromStringECDSA(process.env.BUYER_KEY!),
{ network: 'hedera:testnet' },
);
const client = new x402Client().register('hedera:*', new UptoHederaScheme(signer));
// 402s are now answered with a signed authorisation, automatically.ecrecover returns the alias, and it is the only address form HTS resolves. An ED25519 account cannot sign an authorisation.Advertise a ceiling in the 402. Do the work, then settle exactly what it consumed. The fifth argument is the whole scheme.
import { x402ResourceServer } from '@x402/core/server';
import { UptoHederaScheme } from 'x402-hedera-upto/upto/server';
server.register('hedera:*', new UptoHederaScheme({
defaultAssets: { 'hedera:testnet': { asset: '0.0.429274', decimals: 6 } }, // USDC
}));
// ...run the work, then charge for exactly what it consumed:
const actual = String(outputTokens * unitPrice);
await server.settlePayment(payload, requirements, undefined, undefined, { amount: actual });
// ^^^^ the 5th argumentThe facilitator submits capture() and pays the network fee, so the buyer never sends a transaction. It supports exact too, so it is a drop-in replacement — not a parallel universe.
import { x402Facilitator } from '@x402/core/facilitator';
import { createUptoFacilitatorSigner, accountEvmAddress } from 'x402-hedera-upto';
import { UptoHederaScheme } from 'x402-hedera-upto/upto/facilitator';
const upto = new UptoHederaScheme(
createUptoFacilitatorSigner('0.0.FAC', key, { proxyContractId: '0.0.PROXY' }),
{ proxyContractId: '0.0.PROXY', chainId: 296,
facilitatorEvm: await accountEvmAddress('0.0.FAC', 'hedera:testnet') },
);
new x402Facilitator().register(['hedera:testnet'], upto)
.registerExtension({ key: 'offer-receipt' })
.registerExtension({ key: 'meter' });The seller signs four documents — an offer and a price schedule before the work, a receipt and a meter reading after — and anchors them to HCS. Then anyone audits a settlement from the public Mirror Node, trusting nobody.
import { auditSettlement, buildLedger } from 'x402-hedera-receipts';
// one settlement, from HCS + the chain
const verdict = await auditSettlement(bundle, 'hedera:testnet');
// → { ok, violations: ['arithmetic_fraud', ...], captured, claimed, units, unitPrice }
// score every seller on a topic, purely from public data — no database
const ledger = await buildLedger({ receiptsTopicId: '0.0.9557142', network: 'hedera:testnet' });The verdict is a pure function of the seller’s signature and the on-chain Captured event — auditSettlementLogic() takes them directly, no I/O, and is covered by 56 offline unit tests.
Audit a live topic with no install, no key, no account. It reads the public Mirror Node and returns the same verdict from any machine.
npx x402-hedera-receipts audit --topic 0.0.9557142
npx x402-hedera-receipts audit --topic 0.0.9557142 --tx 0.0.X@169... # one settlement, in fullAny MCP-capable agent — Claude Desktop, Cursor, the Hedera Agent Kit — gets three tools: tally_pay, tally_audit_settlement and tally_seller_reputation. The two audit tools need no key at all; they read the public Mirror Node.
{
"mcpServers": {
"tally": {
"command": "npx",
"args": ["-y", "x402-hedera-mcp"],
"env": {
"HEDERA_NETWORK": "hedera:testnet",
"BUYER_ID": "0.0.xxxxxxx",
"BUYER_KEY": "<ecdsa-private-key-hex>"
}
}
}
}tally_pay refuses to sign above TALLY_MAX_CEILING_ATOMIC, refuses hosts outside TALLY_ALLOWED_HOSTS, and refuses private or link-local targets, resolving DNS first. Omit the buyer keys and only the two keyless audit tools load.The same loop runs headless in this repo — an agent with a goal and a budget it will not cross:
npm run agent:auto # honest run, $1.00 budget, six purchases
npm run agent:auto -- --cheat-at 3 # seller turns dishonest mid-run; it gets cut off
npm run agent:auto -- --min-honesty 0.9 # walk away from sellers the chain rates below 90%