Hanzo

Allowance

Package allowance is how much a plan lets you do without paying, and how much of it you have left today.

Package allowance is how much a plan lets you do without paying, and how much of it you have left today.

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

Specification

HIP-1101 · Allowance — The Free Lane's Ceiling — Draft · read the specification →

/v1/allowance is how much a plan lets a caller do without paying, and how much of it they have left today. Money gates every priced route, but a route priced at zero leaves the balance gate nothing to refuse — deliberately, so a caller with no wallet can reach the free pool — and the free pool runs on our own compute. The allowance is that lane's ceiling: a COUNT of calls, per subject, per period, taken from the caller's plan. It is implemented in hanzoai/cloud at apps/allowance.

Motivation

Without a ceiling the free lane is unlimited for anyone who can name a free model, and a route stated at zero can still be served by a vendor who bills us. The sibling question — how fast a caller may burn their OWN money — is rollingcap's; this capability bounds how much of OUR compute a caller with no money may take (manifest/apps.go:139-142).

Specification

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

§1 Count and money never stand in for each other

A free call costs nothing, so a balance can neither express it nor refuse it; a paid call is bounded by the wallet and MUST never reach this store. This is what lets the free tier be generous without issuing credit we do not owe.

§2 The store

One system SQLite database, allowance, opened through sqlpool.Open and so encrypted under the process key (apps/allowance/store.go). One row per subject; the period is IN the row, which is why nothing resets anything — a count carries the day it was made on, so yesterday's row reads as zero today and is overwritten by the first call of the new day. No scheduler, no sweep, no window during which a job has not run yet.

§3 Addresses

GET /v1/allowance is the one public operation, typed: what the CALLER has left this period and when it turns over. The subject is resolved from the validated principal's wallet (principal.WalletOf, apps/allowance/allowance.go:212) and can never be named in the request; an unauthenticated caller is refused. Two further operations live on the internal plane, not at any public address (apps/allowance/rpc.go): allowance_read admits and allowance_take counts. Two ops because there are two moments — a call is admitted before it runs and counted after it answered, and counting the attempt would charge a customer for an outage of ours. The read-and-increment is one statement in one transaction, so two served calls arriving together cannot both write the same count.

§4 Tenancy

On the plane, the org is the caller's own (cloud.Who(ctx).Org) and cannot be named in the input; it selects the TIER whose ceiling applies. The row is addressed by subject alone, and what keeps one caller out of another's count is the subject the gate resolved from a verified credential plus the plane's own boundary — it answers on a socket inside the pod and has no address on the edge.

§5 The ceiling is a platform switch

The per-tier limit is a flags key, editable live through the admin cockpit rather than shipped in the plan catalog, because the number is a marketing dial. A named tier's switch MAY be 0 (unbounded, an admin's decision about a subscriber commerce identified); a caller nobody can name gets the floor, and no setting can turn that off — "we could not tell who this is" MUST never mean "as much as they want".

§6 Money, events, telemetry, stage, upstream

The capability itself is free (plugin/allowance/main.go, cloud.Free) — it gates spend, it does not create it. It publishes nothing to the bus. Beyond the request span it emits structured log lines only. Stage ga: it is the money plane's free-lane half, part of the self-service core. It derives from no OSS upstream.

Rationale

The alternative period model is a reset job. A sweep has a window during which it has not run, and the turnover is then a fact about the scheduler rather than about the data. Making the period part of the row makes turnover a property of reading — already true for every subject at the same instant, including subjects nobody will ever call again.

Security Considerations

The wrong implementation is unmetered free compute: a caller who can choose their own subject spends someone else's allowance, and a caller who can reach take directly inflates a stranger's count to lock them out. Both are closed the same way — the subject comes from the verified credential, and the counting op is reachable only over the in-pod plane. The failure most worth naming is the unnameable caller defaulting open; here it defaults to the floor.

Four surfaces

SurfaceReaches this capability asCoverage
RESTallowance at its own prefix1 operation
CLIhanzo allowance …1 of 1
SDKAllowanceApi in every published client1 method
MCPtool allowance on https://api.hanzo.ai/v1/mcp1 operation

Quickstart

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

Then the first call — a read that needs nothing but the key. GET /v1/allowance, operation get_allowance:

hanzo allowance get

Answers 200 with object — ok.

Endpoints

EndpointWhat it does
GET /v1/allowanceAnswers what the CALLER has left of their plan's free-call allowance this period, and the instant the count starts again.

All Hanzo APIs · Interactive reference

How is this guide?

On this page