Events
An event is one unit of usage. The minimal shape:- Idempotency is enforced, not advisory. A repeated
eventIdempotencyKeyreturns409 Conflict. Generate one unique key per logical event (a UUID is fine) and you can retry sends safely. - Customers resolve by your ID.
customerReferenceIdis the same ID you used when creating the customer. - Cost fields are optional but are the margin story. Send
costAmountat the top level. Put model-aware fields insidecostInput:model,modelProvider,inputTokens, andoutputTokens. The oldercostInput.costUnitsfield is deprecated. Stamp what the usage cost you, and per-customer margin falls out of the same ledger that bills. - Revenue is computed at ingestion from the plan’s pricing rule and stored on the event, not reconstructed at invoice time.
- Credit-backed features return a deduction receipt. When the feature is
backed by a credit model, the ingestion response includes
creditsDeducted,weightApplied,weightId,weightMatch, andremainingBalance— see Credit weights. The fields are absent otherwise.
Entitlements
meta.reason says why (no subscription, entitlement revoked,
limit reached). Checks fail closed: no subscription, unpaid first
invoice, or missing configuration all mean allowed: false.
The intended pattern in your request path:
Quoting the credit cost of a proposed action
POST /entitlements (evaluate) accepts usage.model and returns a
creditQuote — the weight that would apply and the credits the proposed
usage would burn. The model string must exactly match the
costInput.model you’ll send on the event. The quote resolves at request
time; the charge resolves at the event’s occurredAt — a quote, not a
promise. Details in Credit weights.
Correlating a check to the event it authorized
POST /entitlements (the evaluate variant, for simulating proposed usage)
accepts an optional context.flowId. Pass one, or omit it and Tanso
generates one and returns it in the response:
POST /events call that reports the resulting
usage, and the event carries it too. flowId is a plain, indexed string
column on events — not a foreign key, just a shared value you control (or
let Tanso mint) so you can later query “what usage came out of this check.”
It’s optional, and there’s no automatic join between a check and an event
without it. The plain GET /entitlements/{customerReferenceId}/{featureKey}
check doesn’t take a flowId — only the evaluate/simulate endpoint does.
Credit hard limits
Credit deduction and depletion detection happen synchronously during event ingestion. When linked hard-limit pools cannot cover the event, the Client API returns409 Conflict with success: false and a Credit pool depleted
error. The event is not stored and no credits are deducted.
An entitlement check before serving is still the preferred request pattern.
The ingestion rejection protects against stale checks and direct event sends.
See Credits for the deduction model.