hip-1191

HIP-1191: Billing — Invoicing and Metered Usage. Status Final. Hanzo architectural specification.

HIP-1191: Billing — Invoicing and Metered Usage

Abstract

/v1/billing is the canonical capability for billing within the Hanzo Cloud platform. Package billing is your org's balance, what it has spent, and the cards it pays with. The implementation is hanzoai/cloud apps/billing and plugin/billing (HIP-0106, HIP-0139). All operations are native, composable, and authenticated against Hanzo IAM (HIP-0026).

Motivation

Before this specification, billing operations lacked a unified canonical surface or were scattered across disparate endpoints. Under HIP-0139 (§1), every cloud capability maps 1:1 with exactly one plugin binary, one address prefix, one client class, and one authoritative specification. This eliminates duplicate implementations and ensures strict physical isolation, predictable billing, and orthogonal composability across the estate.

Specification

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

§1 Addresses and Operations

The billing capability answers exclusively under its assigned route prefixes:

| Method | Path | Summary | |---|---|---| | GET | /v1/billing/accounts | Answers the caller's billing accounts: the org itself, its currency, when it was opened... | | GET | /v1/billing/accounts/{id}/members | Answers one billing account's roster. | | GET | /v1/billing/alerts | Lists this org's spend caps: the ceiling, its scope, whether it enforces, and how much ... | | POST | /v1/billing/alerts | Opens a spend cap on the caller's own org. | | GET | /v1/billing/alerts/authorize | Answers whether one proposed spend fits inside this org's caps. | | DELETE | /v1/billing/alerts/{id} | Removes one of the caller's spend caps and answers 204. | | PATCH | /v1/billing/alerts/{id} | Changes one spend cap: raise or lower the ceiling, flip enforcement, retune the rate li... | | GET | /v1/billing/balance | Prepaid credit the caller's org can still spend | | GET | /v1/billing/credit-balance | Answers what the caller can spend right now, one entry per currency. | | GET | /v1/billing/credit-balance/breakdown | Answers that same spendable credit split by grant tag, with the earliest expiry under e... | | GET | /v1/billing/credits | Lists the caller's credit grants — every one of them, spent and lapsed and voided inclu... | | POST | /v1/billing/crypto/deposit | Issues a deposit address the caller can send crypto to, on the asset they ask for. | | GET | /v1/billing/crypto/deposit/{id} | Reads one of the caller's own deposit intents back — pending, confirming, or succeeded. | | GET | /v1/billing/crypto/options | Answers which chains and tokens the crypto rail accepts — what an asset picker renders. | | GET | /v1/billing/invoices | Lists the caller's invoices, newest first, with the count beside them. | | POST | /v1/billing/invoices | Raise a draft invoice against a customer | | GET | /v1/billing/invoices/{id} | Read one invoice | | POST | /v1/billing/invoices/{id}/collect | Collect an issued invoice from credits, balance, then card | | POST | /v1/billing/invoices/{id}/issue | Issue a draft invoice, making it collectible | | GET | /v1/billing/invoices/{id}/pdf | Download one invoice as a PDF | | POST | /v1/billing/invoices/{id}/void | Void a draft or issued invoice | | GET | /v1/billing/ledger | Answers the org's own postings inside range=, each as a signed entry: a DEPOSIT CREDI... | | GET | /v1/billing/methods | Cards and accounts on file for the caller | | POST | /v1/billing/methods | Save a card or account for the caller | | DELETE | /v1/billing/methods/{id} | Removes one card or account the caller has saved. | | POST | /v1/billing/mode | Moves this org between sandbox money and real money. | | GET | /v1/billing/payouts | Answers the org's outbound payouts, newest first — amount, destination, status, and the... | | GET | /v1/billing/plans | The plan catalog, priced with whatever offer is in force | | GET | /v1/billing/portal/methods | Cards and accounts on file for the caller | | POST | /v1/billing/portal/methods | Save a card or account for the caller | | DELETE | /v1/billing/portal/methods/{id} | DetachPortalMethod is DetachMethod at the address a hosted checkout addresses it by. | | GET | /v1/billing/recharge | Reads the caller's auto-reload rule: top the balance up by amountCents whenever it fa... | | PUT | /v1/billing/recharge | Sets the caller's auto-reload rule, and answers with the rule as stored. | | POST | /v1/billing/recharge/run-all | Sweeps every org's auto-recharge and answers what it did. | | GET | /v1/billing/settings | Answers the PUBLIC half of this org's processor configuration — the ids a browser needs... | | POST | /v1/billing/subscribe/card | Buy a plan with a card | | GET | /v1/billing/subscriptions | Lists the plans the caller holds, with the count beside them. | | POST | /v1/billing/subscriptions/{id}/cancel | End a subscription | | POST | /v1/billing/subscriptions/{id}/reactivate | Put a canceled subscription back on its plan | | GET | /v1/billing/tier | Answers which tier the caller is on, what it allows, and what is left to spend. | | POST | /v1/billing/topup | Charges a card the caller already saved and credits the balance. | | POST | /v1/billing/topup/token | Charges a single-use card token and credits the caller's balance. | | GET | /v1/billing/transactions | Answers one page of the caller's own ledger, newest first: what moved, how much, when, ... | | GET | /v1/billing/transactions/{id} | Reads one ledger entry by its id. | | GET | /v1/billing/usage | Every billed call the caller's org made, attributed to a product | | GET | /v1/billing/usage/accounts | Answers per-account totals for the linked provider accounts the gateway ROUTED this cal... | | GET | /v1/billing/usage/rollup | Answers the caller's month: what their plan includes, what has been consumed against it... | | GET | /v1/billing/wire | Answers where to send a wire top-up: the receiving bank details, with the caller's own ... |

§2 Storage and Physical Isolation

Data is isolated physically per organization using cloud.OrgDB: {DataDir}/orgs/{org}/billing.db. Isolation is strictly enforced at the filesystem and OS level; no cross-tenant queries are permitted. Where temporal or timeseries data is captured, postings are signed and immutably appended.

§3 Authentication and Principal

Every request reaching /v1/billing MUST present a valid Hanzo IAM bearer token (HIP-0026, HIP-0111). Anonymous requests are rejected at the edge gateway before invoking the plugin. The executing principal is extracted from the token and bound to the request context.

Security Considerations

  1. Physical Separation: Each tenant retains an isolated SQLite database file.
  2. Replay & Channel Binding: Direct dials and internal RPCs enforce channel binding over ZAP native transport.
  3. Audit Trails: All state-modifying actions emit immutable audit events to the centralized event plane (HIP-1190).

References