-
Notifications
You must be signed in to change notification settings - Fork 0
HTTP API
Defaults: bound to 127.0.0.1:8080, configurable via Config.http_bind_address. Implemented in src/api/http_server.rs.
Spec §9.1 — batch ingest.
Request:
{
"events": [
{
"event_id": "evt_01H...",
"kind": "Usage",
"account_id": "acc_123",
"product_id": "ai_gateway",
"meter_id": "tokens.input",
"timestamp_ms": 1778954400000,
"quantity": 1240,
"unit": "token",
"source": "agentcore",
"model_id": "claude-sonnet-4",
"dimensions": { "provider": "anthropic" },
"ingested_at_ms": 0
}
]
}Note: ingested_at_ms is overwritten server-side; the client value is ignored.
Response:
{ "accepted": 998, "duplicates": 1, "conflicts": 0, "rejected": 1 }-
accepted— new events that passed dedupe + made it durable. -
duplicates— sameevent_id, same payload (retries). -
conflicts— sameevent_id, different payload (collector bug). Logged. -
rejected— failed validation (empty IDs, non-positive timestamp, >16 dimensions, Correction/Retraction withoutcorrection_ref).
Spec §12.2 — monthly account usage.
Query params:
-
from,to— RFC 3339 timestamps. Required. Half-open[from, to). -
group_by— comma-separated list. Supported:account_id,subscription_id,product_id,meter_id,model_id,source,unit,kind,hour_start_ms,day, or any dimension key. -
product_id,meter_id,model_id— equality filters. -
source—"raw"(force raw scan) or"rollup"(default; uses rollup segments with raw fallback for the open-period tail).
Response:
{
"watermark_ms": 1778950800000,
"lines": [
{
"product_id": "ai_gateway",
"meter_id": "tokens.input",
"model_id": "claude-sonnet-4",
"quantity": "9823000",
"count": 4127
}
]
}quantity is serialized as a string because i128 doesn't fit safely in JSON numbers past 2^53.
watermark_ms is the upper bound (exclusive) below which every hour has been rolled up — anything above is being served from raw events.
COUNT semantics differ for the rollup source: each rollup row counts as 1, not as the number of underlying events. Use source=raw for exact event counts.
Spec §12.3 — raw audit query.
Query params:
-
from,to— RFC 3339 timestamps. Half-open. -
meter_id,product_id— equality filters.
Returns raw event rows (no aggregation):
{
"events": [
{ "event_id": "evt_...", "kind": "Usage", "account_id": "acc_123", ... }
]
}Flexible SQL subset for investigation. Not the billing path.
{ "query": "SELECT meter_id, SUM(quantity) FROM usage_events WHERE account_id = 'acc_x' AND timestamp_ms >= 1000 AND timestamp_ms < 2000 GROUP BY meter_id" }Supported:
SELECT col, ..., SUM(quantity), COUNT(*) FROM (usage_events | usage_rollup_hourly)-
WHERE— AND-only conjunctions of=,IN (...),<,<=,>,>=(range comparisons only ontimestamp_ms/hour_start_ms) GROUP BY col, ...
Rejected with a specific error:
-
ORinWHERE -
SUM(anything but quantity)/COUNT(col)/COUNT(DISTINCT ...) -
SELECT */ aliases /HAVING/ORDER BY/LIMIT - Multi-statement queries
- Anything else not explicitly listed above
Programmatic alternative to SQL — same plan shape as the path-based endpoints but with full filter/metric flexibility:
{
"source": "usage_events",
"account_id": "acc_x",
"from": "2026-05-01T00:00:00Z",
"to": "2026-06-01T00:00:00Z",
"group_by": ["product_id", "meter_id"],
"filters": { "meter_id": ["tokens.input", "tokens.output"] },
"metrics": { "quantity": "sum" }
}Returns OK if the server is running.
400 — invalid from/to parsing, SQL parse error, unknown table, unsupported syntax.
500 — WAL append/sync failure, flusher channel closed.
The body of error responses includes the underlying error message verbatim.