Usage API
Every request you have made, what it cost, and what it was charged on — queryable, paginated, and matching your transaction history exactly.
Endpoints
| Method | Path | Summary |
|---|---|---|
GET | /v1/usage | Request-level usage history, cursor-paginated. |
GET | /v1/usage/summary | Totals for a bounded range. |
GET | /v1/usage/by-model | Spend and billable usage per model. |
GET | /v1/usage/by-api-key | Spend and billable usage per key you own. |
These authenticate with your account session, like the API
keys endpoints — an ak- token is refused.
billable_* is what your charge was computed from. raw_*
is what the model reported, and it is null when the
model reported nothing. They are never the same field and a null is never a
zero — "we do not know" and "it was nothing" are different facts.
Token fields
| Field | Meaning |
|---|---|
billable_input_tokensbillable_output_tokensbillable_total_tokens |
What the charge was computed from. Always present. |
raw_input_tokensraw_output_tokens |
What the model reported. null when it reported nothing. |
charged_units | The settled amount, in integer units. |
reserved_units, released_units |
The hold taken before the request, and the unused part returned after it. |
Where a model returns more than the cap you asked for, the excess is
absorbed and never billed: billable_output_tokens never exceeds
the max_tokens you sent.
Ranges and pagination
startandendare ISO-8601 UTC. The range is[start, end)— end is exclusive, so adjacent ranges never return the same request twice.- Pagination is by opaque
cursor, never by offset. Passnext_cursorback; never construct one. - A row inserted while you page cannot duplicate or hide a row you already received.
- Default page 25, maximum 100. Request-level history spans up to 90 days; aggregates up to 365.
Reading usage
# Request history. Ranges are [start, end) — end is EXCLUSIVE. curl "https://api.astrodyne.ai/v1/usage?limit=25" \ -H "Authorization: Bearer $ASTRODYNE_SESSION_TOKEN" # Totals, and spend per model. curl "https://api.astrodyne.ai/v1/usage/summary" \ -H "Authorization: Bearer $ASTRODYNE_SESSION_TOKEN" curl "https://api.astrodyne.ai/v1/usage/by-model" \ -H "Authorization: Bearer $ASTRODYNE_SESSION_TOKEN"
import os
import httpx
session = {"Authorization": f"Bearer {os.environ['ASTRODYNE_SESSION_TOKEN']}"}
with httpx.Client(base_url="https://api.astrodyne.ai") as http:
summary = http.get("/v1/usage/summary", headers=session).json()
print(summary["request_count"], "requests,", summary["spend_usd"], "USD")
# Page through request history. The cursor is opaque; do not construct one.
cursor = None
while True:
params = {"limit": 100}
if cursor:
params["cursor"] = cursor
page = http.get("/v1/usage", headers=session, params=params).json()
for record in page["data"]:
# billable_* is what you were charged on.
# raw_* is what the model reported, and is None when it
# reported nothing — do not treat that as zero.
print(record["request_id"], record["model"],
record["billable_total_tokens"], record["charged_units"])
if not page["has_more"]:
break
cursor = page["next_cursor"]
const session = { Authorization: `Bearer ${process.env.ASTRODYNE_SESSION_TOKEN}` };
const summary = await (await fetch(
"https://api.astrodyne.ai/v1/usage/summary", { headers: session },
)).json();
console.log(summary.request_count, "requests,", summary.spend_usd, "USD");
// Page through history. The cursor is opaque; never construct one.
let cursor = null;
do {
const url = new URL("https://api.astrodyne.ai/v1/usage");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const page = await (await fetch(url, { headers: session })).json();
for (const record of page.data) {
// billable_* is what you were charged on. raw_* is what the model
// reported and is null when it reported nothing — not zero.
console.log(record.request_id, record.model, record.billable_total_tokens);
}
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);
Filters
| Parameter | Notes |
|---|---|
start | Optional. ISO-8601 UTC. Defaults to 30 days ago. |
end | Optional. ISO-8601 UTC. **Exclusive.** |
model | Optional. Must be a model you can see. |
api_key_id | Optional. Must be a key you own. |
status | Optional. One of the public status values. |
limit | Optional. 1–100, default 25. |
cursor | Optional. From `next_cursor`. |
A model you cannot see and a model that does not exist both
answer 404 model_not_found. An api_key_id belonging
to someone else and one that does not exist both answer
404 api_key_not_found.
Totals
/v1/usage/summary reports counts and spend for a range. Provider
coverage is reported as counts —
raw_usage_available_request_count and
raw_usage_missing_request_count — rather than folded into a
total, because summing an unknown as zero would understate it silently.
What these numbers are
charged_unitsis the amount actually charged. It is never recomputed from today's prices, so it always matches what you actually paid.- Amounts are integer
units— 1 USD = 100,000,000 units — with a decimal string alongside. No floating-point arithmetic touches money. - Totals here match your transaction history to the unit.