Tenants & statements
ModelRig can produce a per-customer statement for the workstreams you run on behalf of your customers: what each one attempted, what was verified, and the true cost you incurred serving them. It is a meter of record — it derives the statement and can hand a counts-only usage record to wherever you bill. It never invoices, taxes, duns, or moves your customers' money.
This page covers three things: how a subject becomes a tenant, what a statement contains, and what it never contains.
How a subject becomes a tenant
A "tenant" is one of your end customers. A request carries its tenant one of two ways:
1. A subject tag. Tag a call with subject — an opaque, customer-side id (hash it yourself if it looks like PII). On the first sighting of a subject in your org, ModelRig lazily materializes a tenant node for it and stamps every matching inference with that node. This is the default for a SaaS app whose one deployment serves many customers.
``ts await rig.run("summarize", { input, tags: { subject: "cus_8f2a…" } }); ``
2. A project-scoped key. Mint a rig_sk_ key bound to a project and the project is the tenant — every call on that key is already attributed. This suits an agency or SI running one key per client.
Resolution order per request: a project-scoped key wins; otherwise the subject tag; otherwise the call is unattributed.
What the tenant node is. A tenant is an ordinary projects row with kind = 'tenant', created under a reserved per-org parent. Its slug is always a hash of (org_id, subject) — never the raw subject — so two customers can never be fused by a near-miss spelling and the id is stable and org-scoped. The only human-facing field is a display name, and if the subject looks like PII the raw value is never stored (the name falls back to a hash stub).
Tenancy comes from the principal, never the payload. The org a tenant lives in is the org of the key (or session) that sent the telemetry. A subject moves a request between your own customers; it can never reach another org's data.
A per-org cap (10 000 tenants) keeps subject meaning customer, not end user — put user / session in ordinary tags. Beyond the cap, a new subject falls to unattributed with a counted cap_overflow, never a silent new node.
What a statement contains
GET /v1/tenants/:project_id/statement?period=YYYY-MM returns a statement for one tenant and one calendar month (UTC). It is derived on every read from your telemetry — never stored — so it always reflects the latest rows, including late arrivals. The list view is GET /v1/tenants?period=, which also always shows an unattributed row.
A statement carries:
- attempted · verified · billable. attempted is the runs attributed to the tenant. verified is the subset that passed deterministic conformance — a
run-outcome@v1deterministic pass or a schema-conformant artifact. A model judge or a human grade shows up as quality context and never makes a run verified. billable is derived from verified (in this release they are equal; rate cards arrive later). - True cost, in integer cents, decomposed the same way the cost side settles: input/output tokens and cache reads/writes. Rows for a model with no registry price are shown separately as priced at list, never folded into the exact total.
- Tokens, latency p50/p95, and outcomes grouped by task.
- Period status. A period is open (and marked
partial) until two days after month end, then closed.
You can download a statement as CSV from the console or GET /v1/tenants/:project_id/statement.csv?period=.
What a statement never contains
- No content. Every field is a count, a cent amount, an enum, or a hash — never a prompt, a completion, or any free text. This is enforced by a property test, not a promise.
- No other org's data. Reads are scoped to the caller's organization by the same row-level security that governs every other surface; a foreign
project_idreads the same as one that does not exist (a 404, no existence oracle). - No invented history. A tenant's statement begins the first time it is seen; there is no retroactive backfill, and the statement names its
first_seen.
What it is not
A statement is a meter, not a billing system. ModelRig does not invoice your customers, compute tax, run collections, or move money on your behalf. The usage record it can export is a counts-only contract you feed into whatever billing system you already run.