Usage & Cost¶
Per-app usage records and billing rollups. Usage is metered per app; billing is aggregated per group. Costs are derived from the pricing table (the rate in effect at record creation is snapshotted onto each row).
Environment
These routes take no environment query parameter — the API process is
bound to a single environment and resolves it server-side.
Scope
All routes are caller-scoped. A tenant sees only their own group's apps;
a platform-admin caller (platform_wide) spans every group. Cross-tenant
lookups return 404 (existence-hiding), never 403.
Endpoints¶
| Method | Path | Scope | Description |
|---|---|---|---|
GET |
/api/usage/{app_name} |
read | Raw usage records for an app |
GET |
/api/usage/{app_name}/summary |
read | Billing summary for one app |
GET |
/api/usage/report/all |
read | Usage across every app the caller can see |
GET |
/api/usage/group/{group_slug}/summary |
read | Per-group invoice-shaped rollup |
Usage records¶
| Query | Type | Default | Notes |
|---|---|---|---|
record_type |
string | — | Filter by record type (e.g. build, container_runtime) |
since |
ISO-8601 | — | Only records started at/after this timestamp (422 if unparseable) |
status |
string | — | Filter by record status |
limit |
int | 100 |
Max 500 |
Response: 200 OK
{
"records": [
{
"id": "550e8400-...",
"app_name": "gallery",
"branch": "main",
"service_name": "web",
"record_type": "container_runtime",
"status": "completed",
"started_at": "2026-07-20T10:00:00Z",
"completed_at": "2026-07-20T11:00:00Z",
"duration_seconds": 3600,
"memory_mb": 256,
"rate_applied": 0.018,
"cost": 0.018
}
],
"count": 1
}
App summary¶
Aggregates the app's records into totals per record type. since is optional
(422 if unparseable).
Response: 200 OK
{
"app_name": "gallery",
"environment": "dev",
"builds": {
"count": 5,
"total_seconds": 900,
"total_minutes": 15.0,
"cost": 0.05
},
"container_runtime": {
"web": {
"count": 24,
"total_hours": 24.0,
"memory_mb": 256,
"gb_hours": 6.0,
"cost": 0.432
}
},
"active_containers": [
{"service_name": "web", "instance_id": "…", "memory_mb": 256, "started_at": "2026-07-20T10:00:00Z"}
],
"backups": {
"count": 3,
"total_seconds": 42,
"total_size_mb": 128,
"cost": 0.0012
}
}
container_runtime is keyed by service name, so a multi-service app shows a
per-service breakdown. active_containers lists what is running right now,
regardless of since.
Report — all visible apps¶
Returns usage grouped by (app_name, record_type) across every app the caller
can see. Platform admins span all groups; tenants are filtered to their own
group's apps.
{
"environment": "dev",
"records": [
{
"app_name": "gallery",
"record_type": "container_runtime",
"count": 24,
"total_seconds": 86400,
"max_memory_mb": 256,
"total_cost": 0.4320
}
]
}
Group summary (invoice rollup)¶
The per-group billing unit. Aggregates every usage record owned by the
group — keyed on the stamped group_id, so the roll-up survives app deletion
or rehoming — into a per-app / per-record-type breakdown plus a grand total.
This is the invoice-shaped view the dashboard and mecca usage group consume.
A caller may only read their own group's bill: an unknown slug, or a slug
belonging to another group (for a non-platform_wide caller), returns 404.
| Query | Type | Notes |
|---|---|---|
since |
ISO-8601 | Optional lower bound on started_at (422 if unparseable) |
Response: 200 OK