Read record counts by collection, operator and client counts, and Jetstream status. Every endpoint needs stats:read, or the platform key.
const TOKEN = "hv_..."; // your API keyconst headers = { Authorization: `Bearer ${TOKEN}` };const TOKEN = "hv_..."; // your API keyconst headers = { Authorization: `Bearer ${TOKEN}` };let token = "hv_..."; // your API keytoken := "hv_..." // your API key# All examples assume $TOKEN is an API key (hv_...)AUTH="Authorization: Bearer $TOKEN"Record counts
Section titled “Record counts”GET /admin/statsinterface CollectionCount { collection: string; count: number;}
interface Stats { total_records: number; collections: CollectionCount[];}
const response = await fetch("http://127.0.0.1:3000/admin/stats", { headers,});const data: Stats = await response.json();const response = await fetch("http://127.0.0.1:3000/admin/stats", { headers,});const data = await response.json();let client = reqwest::Client::new();let response = client .get("http://127.0.0.1:3000/admin/stats") .bearer_auth(token) .send() .await?;let data: serde_json::Value = response.json().await?;req, _ := http.NewRequest("GET", "http://127.0.0.1:3000/admin/stats", nil)req.Header.Set("Authorization", "Bearer "+token)resp, err := http.DefaultClient.Do(req)curl http://127.0.0.1:3000/admin/stats -H "$AUTH"Response: 200 OK
{ "total_records": 12345, "collections": [{ "collection": "xyz.statusphere.status", "count": 500, "indexed": true }]}indexed is false for a collection that still has records but is no longer indexed.
Admin and client counts
Section titled “Admin and client counts”GET /admin/stats/countsReturns the number of operators (seats, including those with superadmin) and registered API clients. It is cheap to call often, unlike the record counts above. Requires stats:read.
const response = await fetch("http://127.0.0.1:3000/admin/stats/counts", { headers,});const data = await response.json();const response = await fetch("http://127.0.0.1:3000/admin/stats/counts", { headers,});const data = await response.json();let client = reqwest::Client::new();let response = client .get("http://127.0.0.1:3000/admin/stats/counts") .bearer_auth(token) .send() .await?;let data: serde_json::Value = response.json().await?;req, _ := http.NewRequest("GET", "http://127.0.0.1:3000/admin/stats/counts", nil)req.Header.Set("Authorization", "Bearer "+token)resp, err := http.DefaultClient.Do(req)curl http://127.0.0.1:3000/admin/stats/counts -H "$AUTH"Response: 200 OK
{ "users": 3, "api_clients": 2}Jetstream status
Section titled “Jetstream status”GET /admin/jetstream/statusThe live Jetstream consumer’s state since the process started. Requires stats:read; the platform key may call it too. This route exists only when the instance’s records come from Jetstream, which is the default.
Response: 200 OK
{ "protocol": "v2", "host": "jetstream1.us-east.bsky.network", "connected": true, "compression": true, "dictionary_id": 3, "applied_seq": 18300422, "applied_time_us": 1793390000000000, "lag_ms": 412, "worker_queue_depths": [0, 2, 0, 0, 1, 0, 0, 0], "worker_busy_since_ms": [null, 1793390000100, null, null, null, null, null, null], "now_ms": 1793390000512}Unknown values are an explicit null: protocol, host, dictionary_id, applied_seq, applied_time_us and lag_ms are all null before the first connection or event, and the two worker arrays are empty until the worker pool starts.
| Field | Meaning |
|---|---|
protocol | v2 (subscribeEvents) or v1 (/subscribe); null before the first connection |
host | The Jetstream host from JETSTREAM_URL |
connected | Whether a subscription is open now |
compression | Whether frames arrive zstd-compressed |
dictionary_ | The zstd dictionary in use, or null |
applied_ | The newest event that it and every event before it have been applied: the position saved for a restart. null on v1, which has no seq |
applied_ | When Jetstream witnessed that event, in microseconds since the Unix epoch |
lag_ | Milliseconds from applied_time_us to now |
worker_ | Events waiting in each worker’s queue, one entry per JETSTREAM_WORKERS. The event a worker is applying or retrying is not counted |
now_ | Server time when the snapshot was taken, in milliseconds since the Unix epoch. Subtract worker_busy_since_ms from it rather than using your own clock |
worker_ | One entry per worker: when its current event started, in milliseconds since the Unix epoch, or null when idle. An old value with an empty queue means the worker is stuck retrying |
© HappyProto

