# Get Usage

- **Method:** `GET`
- **Path:** `/api/v1/usage`
- **Operation ID:** `get_usage`
- **Tags:** usage

This tenant's usage for one calendar month: the meters, the runs behind them, and the totals.

Your own tenant and no other - the ledger is filtered by the tenant the request's key belongs to.
A month you ran nothing in is an empty report, not a 404.

## Effective servers

- `https://api.saram.sh`

  Saram

## Authentication

- **HTTPBearer**: HTTP bearer

  a Saram API key (`sk_saram_<env>_...`) or a person's AuthKit access token, as `Authorization: Bearer <credential>`. Both are told apart by shape and produce the same principal.

## Query parameters

- **`period`**: `string | null`

  The calendar month to report, YYYY-MM, in UTC. Omitted, it is the month it is now. A month you ran nothing in answers with zero totals, not a 404.

## Responses

### 200 Successful Response

**Content type:** `application/json`

schema: `UsageReport`, no additional properties

One month of your tenant's usage: the meters, the runs behind them, and the totals (`GET /api/v1/usage`).

Your own tenant and no other: the ledger is filtered by the tenant the request's key belongs to, so a
neighbour's run is not in these figures and cannot be. `GET /api/v1/usage.csv` is the same report as the
file an invoice is written from.

**One meter is billed and four are reported.** `billable_usd` is the month's bill: billed steps at
`step_price_usd`, less `included_steps`, plus `monthly_fee_usd`. The model spend, the session count and
the browser seconds are here so you can see what your keys spent and how long your personas were in your
product; none of them is multiplied by anything. The arithmetic is served rather than left to the
client, so a screen and an invoice cannot disagree.

- **`from` (required)**: `string`, format: `date-time`

  First moment of the period, inclusive (UTC).
- **`period` (required)**: `string`

  The calendar month these figures cover, YYYY-MM, in UTC.
- **`plan` (required)**: `string`

  pilot, byo or hosted: the price list this usage is invoiced under.
- **`tenant_id` (required)**: `string`
- **`tenant_name` (required)**: `string`
- **`tenant_slug` (required)**: `string`
- **`to` (required)**: `string`, format: `date-time`

  First moment of the next period, exclusive (UTC).
- **`billable_usd`**: `number`, default: `0`

  What Saram bills you for this month, to the cent: billed steps at the price in force when each run ran, less included\_steps, plus monthly\_fee\_usd. Model spend on your own keys is not in it.
- **`billed_steps`**: `integer`, default: `0`

  The month's billed steps: the persona loop's (role actor), never the reproduction replay's. This, not totals.steps, is what billable\_usd is a multiplication of.
- **`house_models`**: `boolean`, default: `false`

  True when Saram has agreed to carry this tenant's model spend, so runs on a bring-your-own-keys plan may sign their model calls with a Saram-held credential. It changes no figure here - the steps bill at the plan's price either way - and it is what explains a model\_usd\_hosted total that is not zero on such a plan.
- **`included_steps`**: `integer`, default: `0`

  Billed steps the plan's monthly fee covers before the step price applies.
- **`meters`**: `array`

  Per meter and role, summed over the period's runs.

  **Items:**

  schema: `UsageMeter`, no additional properties

  One line of the table of meters: how much of one meter one model caller used in the period.
  - **`meter` (required)**: `string`

    steps (one body tool call, the platform fee's unit), sessions (persona sessions that ran a step), browser\_seconds (pool time), model\_usd\_hosted (model spend on a Saram-held credential), model\_usd\_byo (the same on your own provider key, which the invoice charges at $0) or usage (persona steps weighted by how long each took, recorded per session; reported, not billed).
  - **`quantity` (required)**: `number`

    In the meter's own unit: a count, seconds, or USD.
  - **`role`**: `string | null`

    Which model caller the quantity is attributed to: actor, judge or reproduction. The counting meters are the actor's; a model meter is written per role that had anything priced.
- **`model_usd_complete`**: `boolean`, default: `false`

  Whether the model meters cover every model caller in a run: the persona loop under role actor, the judge and the reproduction check under their own roles. A run metered before the judge was priced (2026-09-25) carries the persona loop's spend alone, so a month reaching back past that is a floor for those runs. The step meter is complete.
- **`monthly_cap_usd`**: `number | null`

  On a plan that bills steps (pilot): what this month may bill before a new run is refused with a 402. Absent means no cap. The refusal compares billable\_usd below against this figure. Not a limit on a plan that prices Usage (free, pro), whose runs are limited by the available balance instead.
- **`monthly_fee_usd`**: `number`, default: `0`

  The plan's monthly fee, included in billable\_usd.
- **`provider`**: `object`, schema: `ProviderSpend`, no additional properties

  Your model provider's estimated bill for the month: shown apart, never added to usage.usage\_usd.
  - **`complete`**: `boolean`, default: `false`

    Whether it covers every model caller in a run: the persona loop, the judge and the reproduction check, each under its own role. A run metered before the judge was priced (2026-09-25) carries the persona loop's spend alone, so a month reaching back past that is a floor for those runs.
  - **`model_usd_byo`**: `number`, default: `0`

    Model spend on your own provider keys, estimated at the provider's list price: their invoice, not a charge from Saram. A ChatGPT login's calls are included in that plan and are not priced here.
  - **`runs`**: `array`

    Per run with any spend, oldest first.

    **Items:**

    schema: `ProviderRun`, no additional properties

    One run's model spend on your own provider key, estimated at list price.
    - **`model_usd_byo` (required)**: `number`
    - **`run_id` (required)**: `string`
- **`runs`**: `array`

  The runs metered in the period, oldest first.

  **Items:**

  schema: `UsageRun`, no additional properties

  One run's line on the invoice: its meters with the roles collapsed, because a line is money per run.
  - **`occurred_at` (required)**: `string`, format: `date-time`

    When the run finished, which is the moment its usage is dated.
  - **`run_id` (required)**: `string`
  - **`billable_usd`**: `number`, default: `0`

    What this run adds to the month's bill: its billed steps, less any covered by the plan's included allowance, at the step price in force when it ran. The plan's monthly fee is not in it - that is on the month, not on a run.
  - **`billed_steps`**: `integer`, default: `0`

    The steps this run is billed for: the persona loop's (role actor), never the reproduction replay's, which are included. Equal to steps until replay steps are counted.
  - **`browser_seconds`**: `number`, default: `0`
  - **`caller`**: `string | null`

    Who started it, as GET /runs reports it. Absent when nobody was identified.
  - **`model_usd_byo`**: `number`, default: `0`
  - **`model_usd_hosted`**: `number`, default: `0`
  - **`sessions`**: `integer`, default: `0`
  - **`steps`**: `integer`, default: `0`
- **`step_price_usd`**: `number`, default: `0`

  USD per billed step under your plan, or your own agreed price where one was set. The price in force at the end of this period; a run is billed at the price in force when it ran, so across a mid-month price change this figure times billed\_steps is not billable\_usd, and the per-run billable\_usd figures say why.
- **`totals`**: `object`, schema: `UsageTotals`, no additional properties

  Per meter, roles collapsed.
  - **`browser_seconds`**: `number`, default: `0`
  - **`model_usd_byo`**: `number`, default: `0`
  - **`model_usd_hosted`**: `number`, default: `0`
  - **`sessions`**: `integer`, default: `0`
  - **`steps`**: `integer`, default: `0`
- **`usage`**: `object`, schema: `UsageCharges`, no additional properties

  The month's prepaid Usage by run and by persona, with its refunds: Saram's charge on a plan that prices Usage. Read from the credit ledger, apart from the step meters above.
  - **`personas`**: `array`

    Per persona, most Usage first, then by persona\_id; deleted personas included.

    **Items:**

    schema: `UsagePersona`, no additional properties

    One persona's Usage in the month, under the name it had when its runs ran (section 2.3).

    Grouped by `persona_id`, which carries the version: `dana_roofer_novice@1` and `@2` are two lines. A persona
    that was renamed keeps the name its sessions were settled under; one that has since been deleted keeps its line
    and says so, because the money it used is still money you spent.
    - **`deleted` (required)**: `boolean`

      True when the persona no longer exists: checked when this report is read, so a line can say 'Dana (deleted)' and still carry every dollar its sessions cost.
    - **`persona_id` (required)**: `string`

      The persona's address as the run named it: id, or id\@version.
    - **`refunded_usd` (required)**: `number`

      Given back for its sessions that failed on Saram's side.
    - **`runs` (required)**: `integer`

      How many runs it took part in this month.
    - **`sessions` (required)**: `integer`

      Its sessions settled this month.
    - **`usage` (required)**: `number`

      The Usage its sessions used, refunded ones included, to 0.001.
    - **`usage_usd` (required)**: `number`

      What that cost you, net of refunds.
    - **`persona_label`**: `string | null`

      Its display name as recorded when its latest session this month was settled - not as it reads now. Absent for a persona that declared no name; show persona\_id then.
  - **`refunded_usd`**: `number`, default: `0`

    Given back this month for sessions that failed on Saram's side.
  - **`refunds`**: `array`

    Every session refunded this month, oldest refund first, then by run\_id and session\_id.

    **Items:**

    schema: `UsageRefund`, no additional properties

    One session that was not charged because it failed on Saram's side (section 2.4): debited, then refunded
    whole, and both kept, so the Usage it would have cost stays visible.
    - **`amount_usd` (required)**: `number`

      What was given back: the whole of the session's debit.
    - **`refunded_at` (required)**: `string`, format: `date-time`
    - **`run_id` (required)**: `string`
    - **`session_id` (required)**: `string`
    - **`usage` (required)**: `number`

      The Usage the session used before it failed, to 0.001.
    - **`fault`**: `string`, const: `"saram"`, default: `"saram"`

      Whose failure it was. Always saram: the harness - the browser pool, a lost worker, a setup step in Saram's own code. A session your model provider or your product ended is charged, and is not here.
    - **`note`**: `string | null`

      The refund's reason as the ledger recorded it.
    - **`persona_id`**: `string | null`
    - **`persona_label`**: `string | null`

      As recorded when the session was settled.
  - **`runs`**: `array`

    Per run, oldest settlement first, then by run\_id.

    **Items:**

    schema: `UsageChargeRun`, no additional properties

    One run's Usage in the month, from the credit ledger: what it used and what that cost, refunds apart.
    - **`refunded_usd` (required)**: `number`

      Given back for its sessions that failed on Saram's side; each one is also in refunds.
    - **`run_id` (required)**: `string`
    - **`sessions` (required)**: `integer`

      Its persona sessions settled this month.
    - **`settled_at` (required)**: `string`, format: `date-time`

      When the run's last session was settled this month: the moment its Usage was charged.
    - **`usage` (required)**: `number`

      The Usage its settled sessions used, refunded ones included, to 0.001.
    - **`usage_usd` (required)**: `number`

      What that Usage cost you, net: refunded\_usd is already taken off.
    - **`caller`**: `string | null`

      Who started it, as GET /runs reports it. Absent when nobody was identified.
  - **`sessions`**: `integer`, default: `0`

    Persona sessions settled this month.
  - **`usage`**: `number`, default: `0`

    The month's Usage, refunded sessions included, to 0.001.
  - **`usage_price_usd`**: `number | null`

    USD per Usage on your plan, in force at the end of the month. Absent on a plan billed in steps. A session is charged at the price in force when it ran.
  - **`usage_usd`**: `number`, default: `0`

    What the month's Usage cost you, net of refunds: the total a screen prints as Saram's charge. Your model provider's bill is never in it (see provider).

**Example:**

```json
{
  "period": "",
  "from": "",
  "to": "",
  "tenant_id": "",
  "tenant_slug": "",
  "tenant_name": "",
  "plan": "",
  "house_models": false,
  "meters": [
    {
      "meter": "",
      "role": "",
      "quantity": 1
    }
  ],
  "totals": {
    "steps": 0,
    "sessions": 0,
    "browser_seconds": 0,
    "model_usd_hosted": 0,
    "model_usd_byo": 0
  },
  "runs": [
    {
      "run_id": "",
      "caller": "",
      "occurred_at": "",
      "steps": 0,
      "billed_steps": 0,
      "sessions": 0,
      "browser_seconds": 0,
      "model_usd_hosted": 0,
      "model_usd_byo": 0,
      "billable_usd": 0
    }
  ],
  "model_usd_complete": false,
  "billed_steps": 0,
  "step_price_usd": 0,
  "included_steps": 0,
  "monthly_fee_usd": 0,
  "monthly_cap_usd": 1,
  "billable_usd": 0,
  "usage": {
    "usage_price_usd": 1,
    "usage": 0,
    "usage_usd": 0,
    "refunded_usd": 0,
    "sessions": 0,
    "runs": [
      {
        "run_id": "",
        "caller": "",
        "settled_at": "",
        "sessions": 1,
        "usage": 1,
        "usage_usd": 1,
        "refunded_usd": 1
      }
    ],
    "personas": [
      {
        "persona_id": "",
        "persona_label": "",
        "deleted": true,
        "runs": 1,
        "sessions": 1,
        "usage": 1,
        "usage_usd": 1,
        "refunded_usd": 1
      }
    ],
    "refunds": [
      {
        "run_id": "",
        "session_id": "",
        "persona_id": "",
        "persona_label": "",
        "fault": "saram",
        "usage": 1,
        "amount_usd": 1,
        "refunded_at": "",
        "note": ""
      }
    ]
  },
  "provider": {
    "model_usd_byo": 0,
    "complete": false,
    "runs": [
      {
        "run_id": "",
        "model_usd_byo": 1
      }
    ]
  }
}
```

### 403 the API key lacks the required scope

### 422 Validation Error

**Content type:** `application/json`

schema: `HTTPValidationError`

- **`detail`**: `array`

  **Items:**

  schema: `ValidationError`
  - **`loc` (required)**: `array of (string | integer)`
  - **`msg` (required)**: `string`
  - **`type` (required)**: `string`
  - **`ctx`**: `object`
  - **`input`**: `any`

**Example:**

```json
{
  "detail": [
    {
      "loc": [
        ""
      ],
      "msg": "",
      "type": "",
      "input": null,
      "ctx": {}
    }
  ]
}
```

## Schemas

- `HTTPValidationError` — shown above.
- `ProviderRun` — shown above.
- `ProviderSpend` — shown above.

  What your model provider billed you for this month's runs, estimated: never Saram's charge, and never to be
  added to it (section 2.5). The heading a screen puts over it is "Your model provider (billed by them, not by
  Saram)".
- `UsageChargeRun` — shown above.
- `UsageCharges` — shown above.

  The month's prepaid Usage, from Saram's credit ledger: what your personas used and what it cost you, by run
  and by persona, and the sessions that were not charged.

  Only a plan that prices Usage (Free, Pro) has rows here; a plan billed in steps reports zeros, and its charge
  is `billable_usd` beside this. A session is in the month it was settled in, which is the month it finished.
- `UsageMeter` — shown above.
- `UsagePersona` — shown above.
- `UsageRefund` — shown above.
- `UsageReport` — shown above.
- `UsageRun` — shown above.
- `UsageTotals` — shown above.

  The period's totals per meter, roles collapsed: the figures a price list is applied to.
- `ValidationError` — shown above.
