Skip to content
External Console API

Get Usage

Retrieve request-level usage history for an account and everything beneath it, newest first. This is the endpoint to reconcile against an invoice.

GET https://console-api.siraya.ai/extapi/v1/usage

Query Parameters

start string Default: end − 31 days
ISO-8601, inclusive. A value without a time zone is read as UTC. A bare date such as 2026-09-01 is accepted and read as UTC midnight.
end string Default: now
ISO-8601, exclusive to the end of the second.
account_id string Default: your default account
Must be your own account or a descendant of it. Reads that account and all its sub-accounts. Omit it and your default account — the first entry from GET /accounts — is used. An id outside your subtree returns 404.
model string
Case-insensitive match on model code or model name.
page integer Default: 1
1-indexed page number.
page_size integer Default: 20
Maximum 100. Larger values are clamped rather than rejected.
curl -G https://console-api.siraya.ai/extapi/v1/usage \
  -H "Authorization: Bearer <CONSOLE_TOKEN>" \
  --data-urlencode "start=2026-09-01" \
  --data-urlencode "end=2026-09-08" \
  --data-urlencode "page_size=20"
import requests

url = "https://console-api.siraya.ai/extapi/v1/usage"
headers = {"Authorization": "Bearer <CONSOLE_TOKEN>"}
params = {
    "start": "2026-09-01",
    "end": "2026-09-08",
    "page_size": 20,
}

response = requests.get(url, headers=headers, params=params)
body = response.json()["data"]
for record in body["data"]:
    print(record["request_id"], record["model"], record["cost"])

Example Response

{
  "isSuccess": true,
  "data": {
    "data": [
      {
        "request_id": "req_01J8XK2P9V",
        "timestamp": "2026-09-08T02:24:07Z",
        "account_id": "11111111-2222-3333-4444-555555555555",
        "model": "gpt-5.4",
        "usage": {
          "prompt_tokens": 10,
          "completion_tokens": 20,
          "reasoning_tokens": 5,
          "cache_read_tokens": 3,
          "cache_write_tokens": 2,
          "total_tokens": 35
        },
        "cost": 0.000091,
        "currency": "USD",
        "status": "success",
        "performance": {
          "latency_ms": 1200,
          "ttft_ms": 300
        }
      }
    ],
    "page": 1,
    "page_size": 20,
    "has_more": true
  }
}

Response fields

Each record in data.data carries:

Field Type Meaning
request_id string The request's identifier. Pass it to Get a single record
timestamp string When the request was made, ISO-8601 in UTC
account_id string The account that made the request — see Sub-account attribution
model string The model code the request ran against
cost number The billed amount, after discounts, to 6 decimal places — see How to read cost
currency string The currency cost is expressed in
status string The outcome of the request. A request that completed reports success
usage object Token counts, below
performance object Timings, below

usage

Field Meaning
prompt_tokens Tokens in the request
completion_tokens Tokens generated in the reply
reasoning_tokens Tokens spent on reasoning, reported separately so they are not counted twice
cache_read_tokens Prompt tokens served from cache
cache_write_tokens Prompt tokens written to cache
total_tokens Sum of the above excluding reasoning_tokens — see How to read total_tokens

Field names compared with inference responses

This record uses different names from the usage object returned by /v1/chat/completions:

This record Chat Completions usage
prompt_tokens prompt_tokens
completion_tokens completion_tokens
reasoning_tokens completion_tokens_details.reasoning_tokens
cache_read_tokens prompt_tokens_details.cached_tokens
cache_write_tokens prompt_tokens_details.cache_creation_tokens
total_tokens (excludes reasoning_tokens, see below) total_tokens (prompt_tokens + completion_tokens)

In a Chat Completions response, prompt_tokens already includes cached and cache-written tokens, and completion_tokens already includes reasoning tokens. Do not add the cache counts to it when reconciling by hand; use cost here for the billed amount.

performance

Field Meaning
latency_ms Total time to complete the request, in milliseconds
ttft_ms Time to first token, in milliseconds

Limits on the window

Limit Value What to do instead
Maximum time range 31 days Page through the month in several calls
Maximum offset 10,000 records Narrow the window with start / end rather than paging deeper

Both are enforced with 400. The 31-day cap covers the monthly reconciliation this endpoint exists for.

Paginate with has_more

There is no total. An exact count means a full scan of the matching set on every page, for a number that cannot change between pages of the same filter. Page until has_more is false.

How to read cost

cost is the billed figure — after discounts — rounded to 6 decimal places, matching the billing standard so this endpoint reconciles against the invoice. It is deliberately not the pre-discount figure.

How to read total_tokens

total_tokens excludes reasoning_tokens, matching the console dashboard. Reasoning is reported on its own field so it can be reconciled without being counted twice.

Sub-account attribution

account_id on each record is the account that made the request. For a limit_quota sub-account that is the sub-account itself, not the root that funds it. One request produces exactly one record.

Get a single record

GET https://console-api.siraya.ai/extapi/v1/usage/{request_id}

Returns the same record shape, not wrapped in a list.

curl https://console-api.siraya.ai/extapi/v1/usage/req_01J8XK2P9V \
  -H "Authorization: Bearer <CONSOLE_TOKEN>"

A request_id outside your account subtree returns 404, not 403 — so the endpoint cannot be used to confirm that another tenant's request exists.

Errors

Status When
400 Unparseable start / end, end at or before start, range over 31 days, or offset past the cap
401 Token missing, malformed, revoked, expired or unknown
403 The issuing user lacks res.request-logs, or their membership is inactive
404 request_id or account_id not found within your subtree
429 Per-user rate limit, returned with error.code RATE_LIMIT_EXCEEDED