Skip to main content
GET /v1/usage returns aggregated buckets — total_credits, total_input_tokens, etc. summed over a window. When you need event-level granularity (one row per billed request, e.g. for FinOps reconciliation against per-call receipts), use GET /v1/usage/events instead.

Shape

curl 'https://api.aurous-labs.com/v1/usage/events?start_time=2026-05-20T00:00:00Z&end_time=2026-05-20T10:00:00Z&limit=50' \
  -H "X-Api-Key: $AUROUS_API_KEY"
{
  "object": "list",
  "data": [
    {
      "id": "cmp_01HXMQ7Z3K8Y2ABCDEFGHJKM",
      "type": "chat",
      "model": "aurous-grow-2.0-pro",
      "status": "completed",
      "created_at": "2026-05-20T08:14:23.491Z",
      "completed_at": "2026-05-20T08:14:25.137Z",
      "duration_ms": 1646,
      "input_tokens": 247,
      "output_tokens": 103,
      "credits_charged": 0.0291,
      "api_key_id": "apikey_01HXMQ7Z3KCDEFGHJKM23ABCDEFGH",
      "user_id": "uuid-of-the-caller-user",
      "request_id": "req_01HXMQ7Z3K8Y2ABCDEFGHJKMZQXVN"
    },
    {
      "id": "emb_01HXMQ7Z3K8Y2ABCDEFGHJKM",
      "type": "embedding",
      "model": "aurous-embed-vision-1.0",
      "status": "completed",
      "created_at": "2026-05-20T08:13:50.221Z",
      "completed_at": "2026-05-20T08:13:50.987Z",
      "duration_ms": 766,
      "input_tokens": 412,
      "output_tokens": 0,
      "credits_charged": 0.00077,
      "api_key_id": "apikey_01HXMQ7Z3KCDEFGHJKM23ABCDEFGH",
      "user_id": "uuid-of-the-caller-user",
      "request_id": "req_01HXMQ7Z3K8YJKMZQXVNCDEFGHABC"
    }
  ],
  "has_more": true,
  "next_cursor": "MDFIWE1RN1ozSzhZMkFCQ0RFRkdISktN..."
}
Each row has the id from the original resource (cmp_* for chat, emb_* for embedding, img_* for image, vid_* for video), the type, the token counts, the credit charge, and pointers back to the API key + user.

Query parameters

Required

  • start_time (RFC 3339) — inclusive lower bound. Maximum lookback: 730 days.
  • end_time (RFC 3339) — exclusive upper bound; defaults to now.

Filters

  • typechat / embedding / image / video (comma-separated for multi-value)
  • statuscompleted / failed / cancelled / processing / pending
  • model — slug or comma-separated multi-value
  • api_key_idapikey_<ulid>
  • user_id — uuid
  • lora_idlora_<ulid> (image/video rows only)

Pagination

  • limit — rows per page (default 100, max 500)
  • cursor — opaque forward-only cursor
The cursor is short-lived and event-stream-specific (different from the /v1/usage page_token). It encodes a (created_at, id) tuple — rows are returned in descending created_at order, ties broken by id ascending.

Use cases

Per-call audit against your ledger

import requests

# Pull every billed call from the last hour, reconcile against your billing ledger
events = requests.get(
    "https://api.aurous-labs.com/v1/usage/events",
    params={"start_time": "2026-05-20T09:00:00Z", "end_time": "2026-05-20T10:00:00Z", "limit": 500},
    headers={"X-Api-Key": "al_live_xxxxxxxxxxxxxxxx"},
).json()

for e in events["data"]:
    expected = your_ledger.find_by_request_id(e["request_id"])
    if expected and abs(expected.credits - e["credits_charged"]) > 0.0001:
        print(f"DRIFT on {e['id']}: ledger {expected.credits} vs platform {e['credits_charged']}")
The request_id on each event matches the Aurous-Request-Id header you got on the original response — that’s the canonical identifier for cross-system reconciliation.

FinOps cost attribution

api_key_id lets you attribute spend to a particular integration or environment (mint a separate API key per workload), and user_id tracks which team member kicked off the call (when calls go via the dashboard or a per-user-token integration).

Replaying a window into your own analytics

For long windows (multiple days), iterate the cursor and stream rows into your warehouse:
import requests

cursor = None
while True:
    params = {"start_time": "2026-05-01T00:00:00Z", "end_time": "2026-05-20T00:00:00Z", "limit": 500}
    if cursor:
        params["cursor"] = cursor
    res = requests.get(
        "https://api.aurous-labs.com/v1/usage/events",
        params=params,
        headers={"X-Api-Key": "al_live_xxxxxxxxxxxxxxxx"},
    ).json()
    for row in res["data"]:
        warehouse.insert(row)  # your sink
    if not res.get("has_more") or not res.get("next_cursor"):
        break
    cursor = res["next_cursor"]
For sustained ingest, prefer webhooks — we POST a signed event the moment each row reaches a terminal status, so you don’t have to poll.

/v1/usage/events vs /v1/usage — when to pick which

Question/v1/usage/v1/usage/events
Total spend on chat last week?✅ aggregate sum❌ would have to sum
Which call cost $50?❌ no per-call✅ per-row charge
Daily chart for the dashboard?✅ pre-bucketed❌ aggregate client-side
Reconcile to my billing ledger?⚠️ aggregate only✅ row-by-row
Audit a specific request_id?✅ filter by request_id (via cursor walk)
Compute p95 latency last hour?✅ duration_ms_p95 baked in⚠️ compute client-side
In short: /v1/usage is the dashboard view; /v1/usage/events is the ledger view.

Where to next?