For the complete documentation index, see llms.txt. Every page is also served as Markdown at its URL followed by .md.

standards
Usage and limitsAccess

Usage and limits

Read what your AI calls cost, who spent it, the workspace's AI credit state and its capacity quotas, from the API, the CLI or the SDK.


Every paid AI call a workspace makes — a chat turn, an image, a dictation, an embedding — is written to a journal before it runs and priced when the AI Gateway reports its cost. Three routes read it back: GET /ai/usage sums the journal over a window, GET /ai/wallet reads the workspace's AI credit state, and GET /quotas reads its capacity quotas.

AI usage

GET /ai/usage aggregates the journal over a window of whole UTC days:

curl "https://api.standards.new/v1/ai/usage?from=2026-09-01&to=2026-09-30&scope=workspace" \
  -H "Authorization: Bearer stndrds_your_api_key"
ParameterDescription
fromFirst day of the window, YYYY-MM-DD. Required.
toLast day of the window, YYYY-MM-DD, included. Required.
scopeme (default) or workspace.

The window is inclusive and read in UTC: from=2026-09-05&to=2026-09-05 covers 2026-09-05 from 00:00:00 to 23:59:59 UTC. It may cover at most 366 days, so a leap year fits whole. A window wider than that, a from after to, a date that is not YYYY-MM-DD and a day that does not exist (2026-02-30) are refused with 400 SCHEMA_VALIDATION_FAILED.

Scope

  • scope=me reads your own usage, including what agents spent while working for you. It needs no grant.
  • scope=workspace reads every member's usage and adds the per-member breakdown. It needs billing:read; without it the request is refused with 403 SCHEMA_FORBIDDEN. See Roles and permissions.

The report

An abridged answer — every breakdown row also carries the fields of totals:

{
  "from": "2026-09-01",
  "to": "2026-09-30",
  "scope": "workspace",
  "totals": {
    "confirmedCostUsd": "0.186",
    "estimatedCostUsd": "0.006",
    "pendingCount": 3,
    "calls": 13,
    "inputTokens": 1300,
    "outputTokens": 260,
    "audioInputMs": 12000,
    "outputCount": 1
  },
  "byDay": [{ "day": "2026-09-01", "confirmedCostUsd": "0.13" }],
  "byModality": [{ "modality": "text", "confirmedCostUsd": "0.144" }],
  "byModel": [{ "model": "openai/gpt-5", "provider": "openai", "confirmedCostUsd": "0.144" }],
  "byMember": [{ "displayName": "Bob", "actorType": "user", "confirmedCostUsd": "0.1" }]
}

totals and every breakdown row carry the same fields:

FieldMeaning
confirmedCostUsdMoney the AI Gateway reported for the calls, or that was looked up from it afterwards.
estimatedCostUsdThe cost of successful calls the Gateway never priced: the model catalogue's estimate, else the estimate taken when the call was admitted.
pendingCountSuccessful calls whose cost is still pending, plus calls still running.
callsEvery call in the window, whatever its outcome.
inputTokens, outputTokensTokens, summed.
audioInputMsAudio sent for transcription, in milliseconds.
outputCountImages and other generated outputs.

Money is a decimal string, never a float. A call's cost is in one of three states, and each counts in one place:

  • confirmed by the Gateway: in confirmedCostUsd.
  • pending, the Gateway has not answered yet: its estimate is in estimatedCostUsd and the call in pendingCount, until the cost is confirmed.
  • unknown, the Gateway will not price it: its estimate is in estimatedCostUsd.

Only a successful call counts an estimate. A failed or expired call adds to confirmedCostUsd only when the Gateway billed it, and a call still running adds no cost until it ends: what it reserved is never counted as spent. All of them count in calls.

The breakdowns:

  • byDay lists every day of the window, in order, zeros included.
  • byModality groups by text, image, audio, video, embedding or decision.
  • byModel groups by the model that answered, else the one requested, with its provider (null when unknown).
  • byMember, with scope=workspace only, groups by the member billed: displayName and actorType.

byModality, byModel and byMember are sorted by confirmedCostUsd plus estimatedCostUsd, highest first.

Members and agents

An agent's spend is billed to the member it works for: a turn in your conversation, or a run you started, counts in your row. An agent working with no member behind it, such as a run a trigger fired, is billed to itself and gets its own row. actorType tells the two apart:

actorTypeThe row is
userA member, with the agents that worked for them folded in.
agentAn agent that spent with no member behind it.
api_keyA key that spent on its own.
systemThe platform's own work, such as classifying the mail of a mailbox connected for the whole workspace.
nullA journal entry whose actor matches no actor of the workspace. A member who was removed keeps their row, as user.

How an agent acts in a workspace is described in Agents as actors.

Wallet in the report

Under a contract or wallet billing mode, the report also carries wallet, the same object GET /ai/wallet returns to you: its dollar amounts only when you hold billing:read. Under metering-only it is absent.

AI credit

GET /ai/wallet reads the workspace's billing mode and AI credit status. It needs agents:read; the dollar amounts need billing:read too and are left out otherwise.

FieldMeaning
modemetering-only, contract or wallet.
statusok, low, exhausted or paused.
availableUsd, reservedUsdDecimal strings; absent under metering-only, and without billing:read.
periodYYYY-MM of the current grant or cap period; absent under metering-only.
credits{ available, version }, when a rate card is configured; absent without billing:read.

Under metering-only the answer is { "mode": "metering-only", "status": "ok" }: usage is recorded, nothing is capped.

Quotas

GET /quotas reads the workspace's capacity, one entry per quota key. It needs billing:read.

KeyCounts
storage.bytesBytes of stored files.
members.seatsActive member profiles.
data.live_recordsRecords not deleted, across every object.
[
  { "key": "storage.bytes", "limit": null, "used": 0, "reserved": 0, "available": null, "version": null }
]
  • used is what is committed; reserved what open reservations hold.
  • available is limit - used - reserved, never below 0.
  • limit: null means nothing is enforced for that key: available and version are null too. When quotas are not enforced at all, every key reads limit: null with used: 0.

From the CLI

standards ai usage --from 2026-09-01 --to 2026-09-30 --scope workspace
standards ai wallet
standards quotas list

ai usage requires --from and --to, and --scope defaults to me; it refuses a date that is not YYYY-MM-DD, or a scope other than me and workspace, before any request. The window's span and order are checked by the API. All three print the API's answer, in any output format.

From the SDK

import { createStandards } from "@standards/client";

const standards = createStandards();

const report = await standards.usage.report({
  from: "2026-09-01",
  to: "2026-09-30",
  scope: "workspace",
});

for (const member of report.byMember ?? []) {
  console.log(member.displayName, member.actorType, member.confirmedCostUsd);
}

usage.report calls GET /ai/usage and returns the report as it is; scope defaults to me. A refused workspace scope throws StandardsAuthError. usage is a client key, so an object named usage is refused by createStandards.

Confirmed money is the Gateway's

Only confirmedCostUsd is money the AI Gateway reported. Add estimatedCostUsd for the full picture of a window whose costs are still arriving, and watch pendingCount fall to 0 as they do.

Next steps