CormorantDocs
Menu

Usage, spending and quotas

Everything your API keys did, what it costs you and how much of each limit is left — per key, project, category, day or hour, in JSON or CSV. The figures come from the same metering and rating as your invoice, so they add up to it to the cent.

Who sees what#

Your key's prefix tells you what it can see:

Key Sees
cma_… account admin key every key (revoked ones included) and project of your account, usage recorded before per-key attribution (key: null), account-level lines, plan allowances
cmr_… standard key only its own usage, requests, limits and alerts

Asking about a key or project you cannot see answers 404, exactly like one that does not exist. Every response carries X-Cormorant-Key-Role, and usage responses say what they cover in scope.

The endpoints#

Endpoint Use it for
GET /v1/usage Totals and groups (group_by=key,project,category,day,hour) with charges
GET /v1/usage/timeseries The same metrics per hour or day, zero-filled, for charts
GET /v1/usage/domains Your busiest fetched domains (90 days)
GET /v1/requests Every request, newest first, with cursor paging (90 days)
GET /v1/quota Every limit and allowance: used, left, projected, status
GET /v1/keys, GET /v1/keys/self Your keys, their roles and limits
POST /v1/alerts A signed webhook at 50 / 80 / 100 % of a limit

Details of every field: API contract.

Charges, not costs#

charge is what you pay: your plan's prices (with your contract rates) in your invoice currency, as a decimal string. billable shows, per price-plan meter, the measured quantity, the included units it used and the amount. Cormorant's own provider costs are not part of customer figures.

Base fee, minimum, contract discount and the free-plan credit belong to the account, not to a key: an account admin key finds them per month under account. On a free plan you still see list-price charges, followed by the 100 % free line, so you know what your usage is worth.

Fresh and final#

Usage is aggregated every 5 minutes. as_of is the moment up to which every request is included; a day is final two hours after it ended, and its figures will not change afterwards. The request ledger is real time — a request's charge appears once it has been aggregated.

Examples#

Charges per key this month, then per key and day as CSV:

curl
curl -sS "https://api.cormorant.ch/v1/usage?group_by=key" \
  -H "Authorization: Bearer $CORMORANT_API_KEY"
curl -sS "https://api.cormorant.ch/v1/usage?from=2026-10-01&to=2026-10-31&group_by=key,day" \
  -H "Authorization: Bearer $CORMORANT_API_KEY" -H "Accept: text/csv" -o usage-october.csv
Python
import csv
import io
import os

import httpx

client = httpx.Client(
    base_url="https://api.cormorant.ch",
    headers={"Authorization": f"Bearer {os.environ['CORMORANT_API_KEY']}"},
)
usage = client.get("/v1/usage", params={"group_by": "key"}).json()
print(f"{usage['totals'].get('charge')} {usage['currency']} as of {usage['as_of']}")
for group in usage["groups"]:
    print(group["key"], group["key_role"], group["requests"], group.get("charge"))

# The same as CSV, e.g. for a spreadsheet or pandas.read_csv.
text = client.get(
    "/v1/usage",
    params={"group_by": "project,category", "from": "2026-10-01", "to": "2026-10-31"},
    headers={"Accept": "text/csv"},
).text
rows = list(csv.DictReader(io.StringIO(text)))

Every failed request of a key yesterday, page by page:

Python
params = {"key": "cmr_AbCdEf", "outcome": "failed", "from": "2026-10-18", "to": "2026-10-18"}
cursor = None
while True:
    page = client.get("/v1/requests", params={**params, "cursor": cursor} if cursor else params)
    body = page.json()
    for row in body["requests"]:
        print(row["time"], row["domain"], row["error"], row["request_id"])
    cursor = body["next_cursor"]
    if not cursor:
        break

Where do I stand? Each limit has limit, used, remaining, projected_end_of_period and status (ok, warning from 80 %, exhausted):

Python
quota = client.get("/v1/quota").json()
for key in quota["keys"]:
    for limit in key["limits"]:
        print(key["key"], limit["name"], limit["used"], "/", limit["limit"], limit["status"])
for allowance in (quota.get("customer") or {}).get("allowances", []):
    print(allowance["name"], allowance["used"], "of", allowance["limit"], "included")

Limits and what happens at them#

The operator can give a key a monthly spend cap, monthly request quotas (search, fetch, fetch_paid), a rate limit and allowed categories — see Limits & politeness. Every response tells you how much is left:

RateLimit-Policy: "project";q=200;w=1, "key";q=10;w=1
RateLimit: "project";r=187;t=1, "key";r=9;t=1
X-Cormorant-Key-Budget-Remaining: 12.40 USD
X-Cormorant-Quota-Remaining: fetch=18766, search=900

At a limit, requests answer 429 key_quota_exhausted or 429 key_budget_exhausted with Retry-After until the month resets — do not retry those in a loop.

Alerts#

Register a webhook and get an event when a key, project or your account crosses 50, 80 or 100 % of a limit or allowance (once per threshold and month):

curl
curl -sS https://api.cormorant.ch/v1/alerts \
  -H "Authorization: Bearer $CORMORANT_API_KEY" -H 'Content-Type: application/json' \
  -d '{"url": "https://hooks.example.com/cormorant", "thresholds": [80, 100]}'

Store the secret from the answer: it is shown once. Verify each delivery's X-Cormorant-Signature (t=<unix>,v1=<hex>, the HMAC-SHA256 of "<t>.<raw body>") before trusting it — the API contract has a ready-made function. The same events are listed in GET /v1/quota (events).

From an agent#

The MCP server's cormorant_usage tool answers "what did I use and what is left?" in a compact form — see MCP server.

View as Markdown