---
title: "Monthly usage"
method: GET
path: "/v2/workspaces/{id}/usage"
tags: ["Usage"]
---

# Monthly usage

`GET /v2/workspaces/{id}/usage`

## Request

- Base URL: `https://api.infolang.ai`
- URL: `https://api.infolang.ai/v2/workspaces/{id}/usage`
- Auth: one of:
  - HTTP bearer
  - HTTP bearer
  - HTTP bearer

Metered usage for the month (default: current). `meters` breaks the period down per canonical meter — recall, memorize, ingest, storage, egress — each row carrying used/included/overage against the workspace's plan inclusions, plus the informational `chunks_ingested` row. `egress` (tokens returned) has no plan allowance yet, so its `included`/`overage` are `0`; render those columns as — rather than as a zero-sized inclusion. Also carries point-in-time gauges: namespace count and key counts by env.

**Quota pools at the billing account.** Each row's `used` is THIS workspace's own quantity; the number quota is enforced against is the account total in `meters[].account.used`, summed over the workspaces listed in the top-level `account.workspaces`. A bar drawn from `used` against `included` shows a multi-workspace customer a healthy figure and is then contradicted by a refusal — draw `account.used` against `account.included`. `overage` is likewise account-scoped. The four capped meters carry an `account` block; `egress` and `chunks_ingested` do not, because nothing caps them. When the pooled read is unavailable the top-level `account` says so (`status: "unavailable"`) and no row carries a pooled figure — the per-workspace number is never substituted for it.

**Per-workspace breakdown.** Each `account` block MAY carry `by_workspace`: the pooled `used` segmented by contributing workspace, sorted descending and summing exactly to `account.used`. It is computed upstream and forwarded unchanged — do not re-sum or re-sort it. It is OPTIONAL and its absence carries no information: it is omitted both when the upstream reports no breakdown and when THE CALLER MAY NOT SEE EVERY WORKSPACE THE ACCOUNT OWNS. Per-workspace figures are a disclosure the pooled total is not — a credential scoped to some of an account's workspaces can learn the size of the pool it is measured against, but not which siblings make it up — so the field appears only when the caller's workspace visibility is a superset of `account.workspaces` (a session-lane owner, or a credential scoped to `*`). The two omissions are indistinguishable on purpose; treat a missing `by_workspace` as "no segmentation available" and render the pooled bar unsegmented.

Class B read-only — all three lanes, via the IDOR-safe Kairos preflight. The `namespaces` gauge degrades to `0` rather than failing the response when the underlying memories scan cannot be computed, so a usage read does not 502 just because Kairos is down.

Requires the `usage:read` scope. Accepts all three lanes: a session JWT (bounded by the caller's role on this workspace) or an `il_*` machine credential whose own scope set, workspace set and validity window cover it — both ceilings apply and neither can raise the other, so a credential carrying `usage:read` is still refused where the role does not permit it.

A credential with no scope record resolves to `LEGACY_DEFAULT`, which INCLUDES `usage:read` — every key minted before scoping keeps working here.

## Path parameters

- `id` string, required

## Query parameters

- `month` string

## Response `200`

Usage for the month

- object
  - `workspace_id` string, required
  - `month` string, required
  - `used` integer, required
  - `included` integer, required
  - `hard_cap` integer, nullable
  - `overage` object
    - `spend_cents_to_date` integer, required
    - `budget_cents` integer, required
    - `by_meter` object[], required
      - `meter` 'storage' | 'recall', required
      - `over_units` integer, required
      - `cents` integer, required
  - `account` union, required
    - object
      - `status` 'pooled', required
      - `account_id` string, required
      - `workspaces` string[], required
      - `tier` string, required
    - object
      - `status` 'unavailable', required
      - `reason` 'not_configured' | 'not_supported' | 'upstream_error', required
  - `meters` object[], required
    - `meter` 'recall' | 'memorize' | 'ingest' | 'storage' | 'egress' | 'chunks_ingested', required
    - `used` integer, required
    - `included` integer, required
    - `overage` integer, required
    - `account` object
      - `used` integer, required
      - `included` integer, nullable, required
      - `hard_cap` boolean, required
      - `period` string, required
      - `is_stock` boolean, required
      - `by_workspace` object[]
        - `workspace_id` string, required
        - `used` integer, required
  - `pricing` object, required
    - `currency` string, required
    - `per_unit` number, required
    - `amount` number, required
  - `namespaces` integer, required
  - `keys` object, required
    - `live` integer, required
    - `test` integer, required
    - `total` integer, required

## Other responses

- `401`: The credential itself is invalid — absent, unverifiable on the session lane, or rejected by the Kairos preflight on the `il_live_`/`il_test_`/`il_oauth_` lanes — or `credential_expired`, outside its `[not_before, expires_at)` window
- `403`: `forbidden` — the credential is valid but holds NO grant on this workspace, or is not scoped to it. On the il_* lanes this is the IDOR guard: the preflight bound the presented credential to the path `{id}` and it did not match, so no workspace data was read. Or `insufficient_scope` — the credential's scope set or the caller's role does not cover the scope this route requires (named in the message)
- `422`: month must be YYYY-MM

---

[API](https://skmtc.dev/infolang/apis/infolang-api.md) · [All operations](https://skmtc.dev/infolang/apis/infolang-api/llms.txt) · [OpenAPI document](https://skmtc.dev/infolang/apis/infolang-api/revisions/d04bf6de72c8?raw)
