Confluye
Endpoints

Usage

Workspace limits plus the usage ledger, budgets, alerts, and reconciliation.

Usage v1 routes require a workspace bearer API key. 401 / 403 use { ok: false, error: { code, message, retryable }, meta }. Success is { ok: true, data, meta } with meta.contractVersion: "api-contracts.v1".

Mutations require header Idempotency-Key. Replays with the same fingerprint return the stored response; a different body is a conflict.

Session GET /api/usage?workspaceId= returns { usage } without the contract envelope (membership required).

Endpoints

MethodPathDescription
GET/api/v1/usage/limitsSubscription-style usage summary
GET/api/v1/usage/eventsList ledger events
POST/api/v1/usage/eventsAppend a priced event
GET/api/v1/usage/budgetsList budgets
PUT or POST/api/v1/usage/budgetsUpsert a budget
GET/api/v1/usage/alertsList alerts
POST/api/v1/usage/alertsEvaluate alerts now
GET/api/v1/usage/reconciliationCompare ledger vs legacy credits

Limits

GET /api/v1/usage/limitsdata: { usage }. limits[] always use the internal-test caps documented in Usage, budgets, and alerts. Without a billing account to read, usage.plan is "internal-test" and usage.billingEnabled is false.

Viewer keys receive the workspace-safe.v1 aggregate projection without organization billing identifiers, provider/customer coordinates, or invoice URLs. Keys with workspace.secret.read or workspace.write retain the full billing summary.

On a database-backed deployment the summary also carries usage.billing, the organization's billing summary, and usage.plan / usage.billingEnabled are taken from it (usage.plan falls back to "internal-test" while no plan has been chosen). usage.billing.state is one of:

StateMeaning
trialingA trial the owner started is running.
activeA paid plan is current.
gracePayment is outstanding; access continues until graceEndsAt.
restrictedPayment failed past the grace window.
canceledThe subscription ended.
operator_compedBilling is waived by the operator.
unentitledProvisioned but not yet entitled: the account exists, nobody comped it, and no plan or trial has been chosen. Self-provisioned organizations start here, and it is not a trial — the owner still starts one through onboarding.

Events

Query: dateFrom, dateTo (ISO; dateFrom must be earlier than dateTo; dateTo is exclusive), provider, model, usageClass, cursor (base64url { occurredAt, id }), limit (1–100, default 50). groupBy must be provider, model, or usageClass if set.

data: { events, nextCursor, breakdown? }. Bigints serialize as strings; costCredits is a number.

POST required fields: eventKey, provider, model, usageClass, unit, quantity (positive integer string). Optional: inputTokens, outputTokens (non-negative ints, default 0), runId, stepId, requestId, metadata, occurredAt. Server sets costMicros and pricingVersion from the catalog. Mismatched client costMicros / pricingVersion: 400. Duplicate eventKey with the same payload: 200 { event, deduplicated: true }. Different payload: 409 CONFLICT. Created: 201.

Budgets

GETdata: { budgets[] } (limitMicros string, period, warningPercent, enabled).

PUT/POST body: limitMicros (positive bigint string), period (daily | monthly, default monthly), optional warningPercent (1–100 integer, default 80), optional enabled (default false on create). Invalid: 400.

Alerts

GETdata: { alerts[] }. POST (empty body, still needs idempotency) → data: { enabled: true, created[] } for newly opened alerts this evaluation.

Reconciliation

Query legacyCostCredits (required, ≥ 0) and optional dateFrom / dateTo. data includes ledgerCostMicros, legacyCostMicros, deltaMicros (strings), credit floats, and status: balanced or mismatch (tolerance default 0 micros). 1 cost credit = 10_000 micros.

Next steps