Quickstart
Four steps. At the end of them, an agent with no wallet, no key and no USDC has paid a seller and you can read the receipt on HCS. The numbering is a sequence — order carries information.
Read a tab — no install, no key, no account
Every figure the console shows is served over plain HTTP from published data. Nothing here is privileged: try it against the live testnet gateway right now. A brand-new tab starts at a 0.2500 floor.
Spend from it
One POST. The agent holds no key and signs nothing — the gateway pays the seller on its behalf, against a ceiling the agent earned. You do not name a price: the seller states it in its x402 challenge and the gateway reads it.
Handle the refusal
A refusal is a 200 with a rule, not an error to catch. It is the product working. Ask for more than the 0.0500 per-call cap and watch it fire.
Check the arithmetic yourself
The ceiling carries the inputs it was computed from and a hash of them. Rerun the scoring code on those inputs and you get the same hash — without our database, and without trusting this page.
Reading the callouts
Four kinds, distinguished by border and label. REFUSES is Tab-specific and appears on every endpoint that can decline.
POST /v1/spend
Requests a spend against the tab. The gateway performs the six fast-path checks, writes a hold, pays the seller over x402, and returns the seller’s response body.
| Code | Fires when | Agent should | Retry? |
|---|---|---|---|
| PER_CALL_CAP | The request exceeds the 0.0500 per-call cap in force for this tab. | Split the work, or quote first and wait for a ceiling raise. | never |
| WINDOW_CAP | Window spend plus this request would pass the per-window cap. | Retry after the window tick. The countdown is in the response. | later |
| CEILING_EXCEEDED | Outstanding plus holds plus this request would pass the ceiling. | Earn first, or wait for settlement to clear outstanding. | later |
| CONTROL_CLUSTER | The seller is inside the agent's funding ancestry within the hop limit. | Buy from an independent seller. Do not retry the same one. | never |
| SELLER_NOT_ALLOWLISTED | A Starter Tab may only buy from allowlisted sellers. | Graduate the tab with one clean settlement, then retry. | never |
| TAB_FROZEN | The tab is frozen pending operator review. | Stop spending. Surface the freeze to the operator. | never |
The ceiling formula
Displayed as arithmetic, with each term labelled, because a reader has to be able to check it against the CEILING view in the console.
HCS receipt message
Spend, as a sequence
The ten messages
This is the whole protocol. Everything the console shows, everything verify-tab checks and everything a stranger can replay is one of these — there is no private side-channel and no stored row that is not derived from a message on one of the three topics. Field names are the wire names, kept short because HCS charges by the byte and a receipt that needs chunking is one that can arrive in pieces.
The write-ahead order
reserve → pay → commit. The hold is published and awaited to consensus before the seller is called. That costs two to four seconds and buys the one thing a stranger cannot otherwise check: that every debit was authorised before the money moved.
How revenue is weighted
A counterparty’s revenue is not worth its face value. Three reasons zero it outright — the revenue is not independent demand in any amount — and the rest multiply, truncating down at each step in a fixed order, so the result never depends on evaluation order and never rounds in the agent’s favour.
HCS-14 identity
The agent is addressable as a UAID, not only as an account number — and the identifier is derived from what the agent is, so two parties computing it from the same facts get the same string and nobody has to be trusted to issue it.
Parameters are emitted in the documented order and an absent one is omitted rather than left empty — a trailing `nativeId=` would be a claim about an identifier nobody has.
Build on Tab
Four surfaces over one gateway, and deliberately the same ten verbs: @tab/sdk defines the interface, and the MCP server, the Agent Kit plugin and the CLI all bind to it. Two of the ten act; the other eight only read what was published.
Published on npm as @0xdivyanshh/tab-*. The HTTP API needs no install at all — which is why the quickstart above is curl.
MCP — give your own LLM a tab
The shortest path to "my agent can spend money". Add this to Claude Desktop and the model gets seven tools: tab_balance, tab_quote, tab_ceiling, tab_counterparties, tab_receipts, tab_health and tab_spend. It holds no key and cannot produce a transaction — every spend goes through the gateway, against the ceiling.
SDK — ten verbs, two of which act
Eight read and two spend. The read methods return what was PUBLISHED rather than recomputing it: the package cannot import the scoring or graph code, so it is structurally incapable of offering a second opinion about a ceiling.
CLI — the same verbs from a terminal
A refusal exits ZERO, on purpose: it is a normal outcome, and a non-zero exit would teach every shell script that refusing is a fault.
Verify — recompute a published ceiling
The claim this whole project rests on. It reads the ceiling topic through a public mirror node, reruns the real scoring code on the published inputs, and compares both the number and the hash. It needs no database and no credential of ours — which is the point, and why the scoring package has no I/O.