Usage rollups: GET /v1/metrics/usage
Per-day request counts, error counts, and latency stats for the
caller’s API key. Defaults to the last 7 days; max window is 30 days.
| Field | Notes |
|---|---|
totals.requests | All authenticated requests in the window. Health/version endpoints are excluded. |
totals.errors | Anything that responded 4xx/5xx. Includes rate-limit 429s. |
totals.avg_latency | Request-weighted mean of per-day averages. |
by_day[].p95 | Sample-based: the API caps per-day samples at 1,000 to keep the query bounded. |
by_endpoint | Top 50 routes by request count. Path templates collapse to the matched route, not the URL. |
api_requests table, populated by the
usageLogger middleware that runs after auth on every authenticated
request. Logging is best-effort — a write failure never blocks the
response, but it does mean a small number of requests may be missing
from the rollup during database degradation.
Event counts: GET /v1/metrics/events
A view on the events table grouped by phase and kind. Defaults
to the last 24 hours; max 168 (7 days).
failure_rate is failed / total_events over the window. Because the
table includes both API-driven and indexer-driven events,
failure_rate is a true protocol-level health signal — it reflects
on-chain failures (txs that landed and reverted) as well as
infrastructure failures.
Combining the two
Operators usually pull both endpoints into one view:- Usage answers “how much is this API key doing and how fast?”
— surface
totals.requests,errors,p95, and the topby_endpointrows. - Events answers “what did that traffic actually produce
on-chain?” — surface
by_kind(volume by category) andfailure_rate(red-flag panel).
lsh_test_* and
lsh_live_* keys is left to your own dashboard layer.
Retention
api_requestsrows are kept for 30 days, then pruned by a daily job. Long-term aggregates live in your own analytics pipeline (or the upcoming billing tables — see roadmap).eventsrows are kept indefinitely — they’re protocol-level artefacts, not traffic logs, and back the explorer’s history view.
Privacy
api_requests stores HTTP method + path template + status + latency
and the optional client_reference tag. No bodies, no headers, no
query strings. Path templates collapse dynamic segments (/v1/agents/9pK9…
becomes /v1/agents/9pK9) so caller pubkeys are not leaked to other
operators of the same API key.
The Authorization header is hashed at lookup time and only the row
id makes it into api_requests — there is no path that surfaces the
plaintext key after the initial issuance.
