Metering API reference
Base URL: https://r3ckon.com
The metering API accepts usage metadata and nothing else. It exists so gateways, self-hosted stacks, and internal pipelines can feed the ledger without a managed provider connection.
Authentication
Every request carries a bearer key:
Authorization: Bearer aiok_ingest_…
Keys are account-scoped and role-scoped:
aiok_admin_…: full console access plus every API below. This is the key revealed once at signup.aiok_ingest_…: may push usage (both ingest endpoints) but cannot read the console or manage the account.aiok_sdk_…: may push to the SDK feed only.
Only a SHA-256 hash of each key is stored. Rotation is currently by request (info@tahosasystems.com) after billing-email verification.
POST /api/v1/ingest/authoritative
The billing-grade feed: daily (or coarser) aggregates that estimates, retirements, and invoices are computed from.
curl -X POST https://r3ckon.com/api/v1/ingest/authoritative \
-H "Authorization: Bearer $R3CKON_KEY" \
-H "Content-Type: application/json" \
-d '{
"events": [{
"apiConnection": "anthropic",
"model": "claude-sonnet-5",
"region": "us-east-1",
"inputTokens": 18400000,
"cachedInputTokens": 12100000,
"outputTokens": 2300000,
"reasoningTokens": 410000,
"serviceTier": "standard",
"timestamp": "2026-08-04T00:00:00Z"
}]
}'
Response: { "accepted": 1 }
Event fields
| Field | Type | Required | Notes |
|---|---|---|---|
model |
string (1..200) | yes | The provider's model identifier, verbatim. Unknown models estimate under the registry's most conservative class. |
inputTokens |
integer >= 0 | yes | The FULL input stream, including any cached portion. |
outputTokens |
integer >= 0 | yes | Completion tokens. |
region |
string (1..64) | yes | Cloud region code when known (e.g. us-east-1). Unrecognized values estimate under conservative unknown-facility parameters. A recognized code selects that cloud's published facility profile, which can lower the estimate relative to the unknown default, so report the region truthfully; region values are recorded with the event and are auditable. |
timestamp |
ISO 8601 datetime with offset | yes | The period the aggregate covers (use the day start for daily buckets). |
cachedInputTokens |
integer >= 0 | no | The cached SUBSET of inputTokens. Omitted means unreported, not zero. |
reasoningTokens |
integer >= 0 | no | The reasoning SUBSET of outputTokens, where the provider reports it (never billed twice). Omitted means unreported; for reasoning-class models that triggers the methodology's conservative hidden-reasoning multiplier. |
serviceTier |
standard | batch | priority |
no | Batch and priority tiers carry their own energy multipliers. |
apiConnection |
string (1..64) | no | Which source produced this usage; groups the console's per-API filters. Accounts support up to 50 distinct connections. |
endUserPseudoId |
string (<=128) | no | An opaque pseudonymous id if you segment end users. Never send anything identifying. |
The content boundary (HTTP 422)
Every payload is deep-scanned before parsing. If any key anywhere in the
JSON matches a content-shaped name (prompt, completion, content,
messages, message, text, input, output, system, body,
response, query, answer, transcript), the request is rejected with
422 and nothing is stored:
{ "error": "Ingest rejected: payload contains content-shaped key \"prompt\". This platform is metadata-only and must never receive prompt or completion content." }
This is an architectural invariant, enforced by tests, not a policy.
Idempotency and re-submission
Managed connections replace their (connection, window) slice atomically on
every sync. For your own pushes, the same practice applies: if you need to
restate a day, re-push the whole day's aggregates for that
apiConnection after deleting nothing; duplicate submission of the same
window will double-count, so push each window once or contact us to reset
a window.
Errors
| Status | Meaning |
|---|---|
400 |
Malformed JSON, missing events array, or field validation failure (message says which). |
401 |
Missing or unknown bearer key, or a role without ingest rights. |
422 |
Content boundary violation (see above). |
POST /api/v1/usage-events
The SDK feed: identical body and validation, accepted from sdk,
ingest, or admin keys. It powers live views and is never billed
from; billing and retirement always come from the authoritative feed.
Account APIs
The console is built on account-scoped APIs authenticated with your
aiok_admin_… key. The stable, supported surface today:
GET /api/admin/overview: everything the dashboard shows, as JSON: monthly footprint with P05/P50/P90/P95 per category, retirements, credit position, invoices, certificates, connections, filters.GET /api/admin/connections/POST(create) /DELETE /api/admin/connections/{id}/POST /api/admin/connections/{id}/syncwith{ "periodStart": "YYYY-MM-DD", "periodEnd": "YYYY-MM-DD" }.GET /api/admin/certificates/{id}/pdf: the certificate PDF.GET /api/admin/exports/{name}: reporting CSVs (water restoration summary, CDP Water and ESRS E3 inputs).POST /api/admin/billing-portal: a Stripe customer portal session URL.
These return JSON errors in the same { "error": "…" } shape. Endpoints
not listed here (reconcile, seeding) are operator-only and may change.