Usage & keys
Your own usage split by day, key, device, app, platform, model, client or tag, and your API keys with device attribution and tags.
These routes return the same data the hub shows on its usage and keys pages, scoped to the account that owns the calling key. Use them from scripts, the SDKs, the CLI or an agent to answer "what did this machine cost me last week?" without opening the hub.
Usage
GET /v1/usage returns one row per value of group_by (day by default) for a window of UTC days. from and to are inclusive YYYY-MM-DD dates; without them you get the last 30 days including today. A window may be at most 400 days long.
- Group by
day,key,device,app(OAuth client),platform,model,clientortag. - Filter with
key,device,app,platform,modelortag; filters apply before grouping, sogroup_by=model&device=<id>is "which models did this device use". - Columns:
requests,errors,tasks(tasks started),prompt_tokens,completion_tokens,cached_read_tokensandcost_micro_usd— USD micros as a decimal string ("1250000"= 1.25 USD). Divide by 1 000 000 for dollars; never parse it as a float if you sum many rows. - MCP. Agents call the read-only tool
usage_get(days= window ending today, default 30; optionalgroup_by). There is no keys tool on the MCP server: keys stay in the hub, SDKs and CLI. - History. The last 30 days are read from raw usage events; older days come from a daily rollup. Tags live on the key and are joined when you read, so tagging a key re-attributes its whole history.
Keys and tags
GET /v1/keys lists your keys (add include_revoked=true for revoked ones). Each key carries its kind (device, user, app, service), the device_id and platform it was minted on, client_version, tags, timestamps and current: true for the key making the call. The secret is never returned. Keys minted for third-party apps are not listed.
PATCH /v1/keys/{id} replaces the tags of one key: at most 16 tags of up to 32 characters each, [] clears them. Tags are yours to define — a project, a client, a cost centre — and then GET /v1/usage?group_by=tag splits spend along them.
import { Codai } from 'codai-sdk';
const codai = new Codai({ apiKey: process.env.CODAI_API_KEY! });
const byDevice = await codai.usage.get({ from: '2026-09-01', to: '2026-09-30', group_by: 'device' });
const { data: keys } = await codai.keys.list();
await codai.keys.setTags(keys[0]!.id, ['client-acme']);from codai import Codai
codai = Codai(api_key="codai_...")
by_model = codai.usage.get({"group_by": "model"})
keys = codai.keys.list(include_revoked=True)["data"]
codai.keys.set_tags(keys[0]["id"], ["client-acme"])bearerAuthAuthorizationBearer <codai_…>A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).
from?stringFirst day (inclusive, YYYY-MM-DD, UTC). Defaults to 30 days before to.
dateto?stringLast day (inclusive, YYYY-MM-DD, UTC). Defaults to today.
dategroup_by?stringDimension of each row.
"day""day""key""device""app""platform""model""client""tag"key?stringOnly this API key of yours (uuid).
uuiddevice?stringOnly this device (uuid).
uuidapp?stringOnly this OAuth client (app) id.
length <= 64platform?stringOnly this client platform (for example vscode, desktop, android).
length <= 16model?stringOnly this model (the upstream model, else the requested one).
length <= 128tag?stringOnly keys carrying this tag.
length <= 32x-request-id?stringClient correlation id; echoed back as x-codai-trace-id and persisted on the usage row.
length <= 128Usage rows for the window.
application/json- response
Usage of the calling account for one window, grouped by one dimension.
from*stringFirst day of the window (inclusive).
dateto*stringLast day of the window (inclusive).
dategroup_by*string"day""key""device""app""platform""model""client""tag"data*array<>curl -X GET 'https://ai.codai.ro/v1/usage'{ "from": "2019-08-24", "to": "2019-08-24", "group_by": "day", "data": [ { "key": "string", "requests": 0, "errors": 0, "tasks": 0, "prompt_tokens": 0, "completion_tokens": 0, "cached_read_tokens": 0, "cost_micro_usd": "string" } ]}bearerAuthAuthorizationBearer <codai_…>A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).
include_revoked?stringtrue also returns revoked keys.
"false""true""false"x-request-id?stringClient correlation id; echoed back as x-codai-trace-id and persisted on the usage row.
length <= 128Your keys.
application/json- response
data*array<>curl -X GET 'https://ai.codai.ro/v1/keys'{ "data": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "label": "string", "prefix": "string", "enabled": true, "kind": "device", "app": "string", "device_id": "string", "platform": "string", "client_version": "string", "tags": [ "string" ], "created_at": "2019-08-24T14:15:22Z", "last_used_at": "2019-08-24T14:15:22Z", "expires_at": "2019-08-24T14:15:22Z", "idle_expiry_days": 0, "revoked_at": "2019-08-24T14:15:22Z", "current": true } ]}bearerAuthAuthorizationBearer <codai_…>A codai API key (codai_ prefix). Ephemeral tokens from POST /v1/tokens are accepted only by the media surfaces matching their scope (/v1/realtime, /v1/audio/*, /v1/embeddings).
id*stringAPI key id (uuid).
uuidx-request-id?stringClient correlation id; echoed back as x-codai-trace-id and persisted on the usage row.
length <= 128application/json- body
tags*array<>items <= 16The tags now stored on the key.
application/json- response
id*stringuuidtags*array<string>curl -X PATCH 'https://ai.codai.ro/v1/keys/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{ "tags": [ "string" ]}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "tags": [ "string" ]}