Key & activity
Four authenticated reads about the caller: the API key itself, the balance of the account it
belongs to, one generation's full billing record, and a day of usage. All four take the usual
bearer key and only ever answer about that key's own account — a
generation id belonging to someone else gets the same 404 an unknown id gets.
Creating, listing, editing and revoking keys is a separate surface: see the Provisioning API, served to a management key rather than the key it manages.
Monetary fields on /key, /credits and /generation are JSON numbers in USD. Internally every
amount is exact decimal arithmetic; the conversion to a number happens once, at serialisation
(see Pricing & billing). /activity's monetary fields are exact
decimal strings instead — see below.
GET /key
The key used to authenticate the request — its label, limit and spend.
curl https://api-staging.heimdallm.com/api/v1/key \
-H "Authorization: Bearer $HEIMDALL_API_KEY"
{
"data": {
"label": "sk-hd-v1-3f9a12…",
"name": "production",
"limit": 10,
"limit_remaining": 4.5,
"limit_reset": "monthly",
"usage": 5.5,
"usage_daily": 0.61,
"usage_weekly": 2.4,
"usage_monthly": 5.5,
"is_free_tier": false,
"expires_at": null
}
}
| Field | Type | Notes |
|---|---|---|
label | string | The key's display prefix — sk-hd-v1- plus the first six characters. Never the full key. |
name | string | The name given at creation. |
limit | number | null | The key's spend ceiling in USD; null when the key has none. |
limit_remaining | number | null | limit minus the spend in the limit's window (lifetime spend when limit_reset is null). |
limit_reset | string | null | daily, weekly or monthly (UTC windows), or null for a lifetime ceiling. |
usage | number | Lifetime settled spend attributed to this key, USD. |
usage_daily / usage_weekly / usage_monthly | number | Spend in the current UTC day / week / month. |
is_free_tier | boolean | Always false. |
expires_at | string | null | ISO 8601 expiry, when one is set. |
GET /credits
The balance of the account the key belongs to — a personal account, or an organization's shared pool (see Organizations, workspaces & keys).
curl https://api-staging.heimdallm.com/api/v1/credits \
-H "Authorization: Bearer $HEIMDALL_API_KEY"
{ "data": { "total_credits": 100, "total_usage": 12.3 } }
| Field | Type | Notes |
|---|---|---|
total_credits | number | Everything ever credited: deposits, refunds, positive adjustments. |
total_usage | number | Everything ever debited. The balance is the difference. |
GET /generation
The record of one request, by the id returned in the response body and the X-Generation-Id
header. A completed generation has record_state: "recorded". A request with a reservation but no final
record has record_state: "unrecorded"; its execution or accounting may be incomplete. Only
records on the caller's account resolve; anything else is a 404. A missing or empty id is a 400.
curl "https://api-staging.heimdallm.com/api/v1/generation?id=gen-9f2c7e1a4b6d" \
-H "Authorization: Bearer $HEIMDALL_API_KEY"
{
"data": {
"id": "gen-9f2c7e1a4b6d",
"record_state": "recorded",
"model": "deepseek/deepseek-v4-flash-0731-abliterated",
"provider_name": "ImpCC",
"created_at": "2026-08-16T09:12:44.031Z",
"streamed": true,
"cancelled": false,
"latency": 2310,
"generation_time": 1876,
"finish_reason": "stop",
"native_finish_reason": "stop",
"tokens_prompt": 1204,
"tokens_completion": 96,
"usage_reported": true,
"native_tokens_prompt": 1204,
"native_tokens_completion": 96,
"native_tokens_reasoning": null,
"native_tokens_cached": 1024,
"num_media_prompt": null,
"total_cost": 0.0000861,
"usage": 0.0000861,
"cache_discount": null,
"app_id": "my-agent",
"upstream_id": "chatcmpl-8Xb2..."
}
}
For an unrecorded request, final token counts, model/provider attribution, stream flags, timings and cost
are null, not measured zero. reservation gives its recorded state and its amount as an exact decimal
USD string; that reserved estimate is not a charge. usage_observations lists up to the latest 100
provider dispatches separately. Each entry retains nullable token counts, image pixels and decimal
audio seconds, along with usage_reported, observed_at and response_complete. Explicitly reported
zero remains zero. These observations are not summed across retries or declared billable, and a
complete response can contain a provider error. usage_observations_truncated is true when older
attempts are omitted. Reading the record neither releases funds nor retries inference.
A recorded generation says where its token counts came from. usage_reported is true when the
provider sent a usage report, which makes a 0 beside it a count the provider measured; false when
it sent none, in which case tokens_prompt and tokens_completion are null rather than zero — a
stream can deliver a whole answer and end before any usage frame arrives, and an unreported count is
not a request that consumed nothing. It is null on records written before this distinction was kept,
whose zeros are therefore evidence of nothing either way. Nothing unreported is charged for: the
components that can be priced from verified usage are, and the rest is not billed.
Recorded image and video requests can also carry media_billing, a versioned receipt with the frozen
rates and measured quantities used for the charge. It is null where no supported native receipt is
recorded. It contains no prompts or reference media.
| Receipt field | Meaning |
|---|---|
version | 1 for this receipt format. |
basis | The quote time, image/video rail, selected rates, declared units and reserved quantity ceilings. |
measurement | Nullable delivered counts, geometry, exact duration and explicit token partitions. Unknown is null. |
components | Each native meter, its quantity, USD unit rate, charged amount and disposition such as priced, unpriced or unknown. |
totalUsd | Exact decimal USD total of the charged components. |
Quantities use { numerator, denominator } integer strings so a duration such as 97/24 seconds
retains its precision. Unit rates can retain finer precision after a discount; the final amount is
rounded only at the ledger’s 24-decimal USD boundary. Historical pixel counts remain pixel counts
and are not converted into image counts or durations.
The fields below describe a recorded generation; unrecorded requests use the null values described above.
| Field | Type | Notes |
|---|---|---|
id | string | The generation id (gen-…). |
model | string | The model that served the request — or the requested id, when nothing served it. |
provider_name | string | null | The serving provider's display name. |
created_at | string | ISO 8601. |
streamed | boolean | Whether the response was an SSE stream. |
cancelled | boolean | true when the client aborted a stream mid-generation. |
latency | integer | null | Total request time in milliseconds. |
generation_time | integer | null | Milliseconds from first token to completion. |
finish_reason | string | null | Normalised: stop, length, tool_calls, content_filter or error. |
native_finish_reason | string | null | The provider's raw finish reason. |
tokens_prompt | integer | null | Prompt tokens billed (cached tokens included in the count); null where none was reported. |
tokens_completion | integer | null | Completion tokens billed, reasoning included; null where none was reported. |
usage_reported | boolean | null | Whether the provider reported usage at all — see below. |
native_tokens_prompt / native_tokens_completion | integer | null | Prompt/completion tokens exactly as the provider reported them. |
native_tokens_reasoning | integer | null | Reasoning tokens the provider reported; null where it reported no count. |
native_tokens_cached | integer | null | Prompt tokens served from the provider's cache; null where it said nothing about one. |
num_media_prompt | null | Always null — media inputs are not counted per generation. |
total_cost | number | The exact charge in USD — the same figure the response's usage.cost carried. |
usage | number | Equal to total_cost, kept for OpenRouter-client compatibility. |
cache_discount | null | Always null — cache reads are billed at their listed price, not as a discount. |
app_id | string | null | App name from the title headers, or null. |
upstream_id | string | null | The provider's own response id. |
GET /activity
Usage of the key's account over one UTC day, in the row shape OpenRouter's /activity publishes.
date takes YYYY-MM-DD; without it, the current UTC day. Only rows with traffic appear; an empty
day is an empty array.
curl "https://api-staging.heimdallm.com/api/v1/activity?date=2026-08-15" \
-H "Authorization: Bearer $HEIMDALL_API_KEY"
{
"data": [
{
"date": "2026-08-15",
"model": "deepseek/deepseek-v4-flash-0731-abliterated",
"model_permaslug": "deepseek/deepseek-v4-flash-0731-abliterated",
"endpoint_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"provider_name": "ImpCC",
"requests": 412,
"prompt_tokens": 1204442,
"completion_tokens": 96041,
"reasoning_tokens": 15208,
"usage": "0.158824",
"spend": "0.158824",
"byok_usage_inference": "0"
}
]
}
| Field | Type | Notes |
|---|---|---|
date | string | The UTC day the row reports, YYYY-MM-DD. |
model | string | Model id. |
model_permaslug | string | The catalogue id; equal to model. |
endpoint_id | string | null | The serving endpoint's id, where the row names exactly one. |
provider_name | string | null | The serving provider's display name, where the row names exactly one. |
requests | integer | Generations in the row. |
prompt_tokens / completion_tokens | integer | Token totals. |
reasoning_tokens | integer | null | Reasoning tokens across the row's generations; null where none reported a count. |
usage | string | Exact decimal USD charged. |
spend | string | Equal to usage. |
byok_usage_inference | string | Always "0" — the marketplace has no bring-your-own-key inference. |
api_key_hash | string | null | Present only under group_by=key: the row's API key, as a SHA-256 hash. |
group_by sets what one row is: model (default) aggregates a model's traffic across every
endpoint and key that served it; endpoint splits a model's rows by which endpoint served them;
key splits by which API key spent them. Grouping only ever splits a day's rows further — summing
any field over a grouped day's rows equals the same model's row at the default grouping.
api_key_hash restricts the day to one key, by the hash /key and the request
log publish. endpoint_id and provider_name read null
wherever a row's generations do not agree on a single endpoint or provider — under model or key
grouping, a model can be served by more than one.
A malformed date, an unrecognised group_by, or a malformed api_key_hash is a 400. user_id
and workspace_id are accepted and always answered with a 400: this endpoint reports the whole
account behind the key, with no narrower member or workspace scope to ask for. For richer
dashboards — a multi-day series, the ledger, per-key attribution — use your
account page.