Admin API
The admin and data endpoints let you manage projects and pull data programmatically. Everything under /api/* is authenticated with your account API key - find it in the dashboard under Settings. This page covers project management, event and user data, and stats; the analytical queries are on the Queries page. Reports, boards, cohorts, and lexicon governance are managed from the dashboard today and not yet documented here.
Authentication
Send Authorization: Bearer $API_KEY on every /api/* request - either
your superadmin key or a Firebase ID token. A missing or invalid credential
returns 401.
bashcurl https://cohorly-service.velloalabs.com/api/projects \-H "Authorization: Bearer $API_KEY"
Projects
List projects. A superadmin credential sees every project across every org; a user credential sees only their own org's.
Create a project. Creates in the caller's org (superadmin creates in the bootstrap org).
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Required | - | Must be unique within the org. |
Two independent conditions return 409, each with its own message: a name
already used within the org gives "error": "name taken", and hitting the
org's project quota gives "error": "project limit reached".
Delete a project and all of its data. Requires the org owner role (or superadmin).
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
id | integer | Required | - | Path parameter - the project id. |
bashcurl https://cohorly-service.velloalabs.com/api/projects \-H "Authorization: Bearer $API_KEY"
json[{"id": 1,"name": "Production","token": "1c9e2f2a-6a3e-4a54-9b7d-6a2a9d1a7b21","created_at": 1753900800000,"org_id": 1,"event_count": 128340}]
bashcurl -X POST https://cohorly-service.velloalabs.com/api/projects \-H "Authorization: Bearer $API_KEY" \-H "Content-Type: application/json" \-d '{ "name": "mobile-app" }'
json{"id": 4,"name": "mobile-app","token": "9d1a7b21-6a3e-4a54-9b7d-1c9e2f2a6a3e","created_at": 1753900800000}
bashcurl -X DELETE https://cohorly-service.velloalabs.com/api/projects/4 \-H "Authorization: Bearer $API_KEY"
json{ "ok": true }
Event metadata
These GETs accept an optional projectId query param; omitting it targets
your first project, so pass it explicitly when you track more than one app.
Raw event stream, newest first.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | string | Optional | - | Target project id. Defaults to the org's oldest project (or the legacy default project for a superadmin credential). |
limit | integer | Optional | 100 | Max 1000. |
event | string | Optional | - | Filter to one event name. Applies lexicon merge aliasing (matches the canonical event plus its merged children). |
distinct_id | string | Optional | - | Filter to one user. |
from | string (date) | Optional | - | YYYY-MM-DD, inclusive. |
to | string (date) | Optional | - | YYYY-MM-DD, inclusive. |
search | string | Optional | - | Case-insensitive substring match on the event name. |
filters | string | Optional | - | JSON-encoded PropertyFilter[] (same shape as segmentation). Invalid JSON or shape returns 400. |
Distinct event names observed in the project - useful for autocomplete.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | string | Optional | - | Target project id. |
raw | "1" | Optional | - | Bypass lexicon governance (merge collapsing, hidden exclusion) and return observed names untouched. |
Property keys observed on a given event name.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | string | Optional | - | Target project id. |
event | string | Required | - | Event name to inspect. |
raw | "1" | Optional | - | Bypass lexicon governance. |
bashcurl "https://cohorly-service.velloalabs.com/api/events?projectId=1&limit=50&event=Signed+Up" \-H "Authorization: Bearer $API_KEY"
json{"events": [{"id": 10245,"event": "Signed Up","distinct_id": "user-42","time": 1753900800000,"properties": { "plan": "free", "$city": "Lisbon" }}],"total": 8213}
bashcurl "https://cohorly-service.velloalabs.com/api/events/names?projectId=1" \-H "Authorization: Bearer $API_KEY"
json[{ "name": "Signed Up", "count": 8213, "recent_count": 402, "last_seen": 1753900800000 }]
bashcurl "https://cohorly-service.velloalabs.com/api/events/properties?projectId=1&event=Signed+Up" \-H "Authorization: Bearer $API_KEY"
json["plan", "$city", "$browser"]
Users
List user profiles.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | string | Optional | - | Target project id. |
limit | integer | Optional | 50 | Max 500. |
search | string | Optional | - | Substring match on distinct_id or the serialized properties. |
One user's profile plus their last 100 events.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | string | Optional | - | Target project id. |
distinctId | string | Required | - | Path parameter - the user to fetch. |
bashcurl "https://cohorly-service.velloalabs.com/api/users?projectId=1&limit=20" \-H "Authorization: Bearer $API_KEY"
json[{"distinct_id": "user-42","properties": { "plan": "pro", "$name": "Ada Lovelace" },"first_seen": 1751600000000,"last_seen": 1753900800000,"event_count": 214}]
bashcurl "https://cohorly-service.velloalabs.com/api/users/user-42?projectId=1" \-H "Authorization: Bearer $API_KEY"
json{"distinct_id": "user-42","properties": { "plan": "pro", "$name": "Ada Lovelace" },"first_seen": 1751600000000,"last_seen": 1753900800000,"event_count": 214,"events": [{"id": 10245,"event": "Signed Up","distinct_id": "user-42","time": 1753900800000,"properties": { "plan": "free" }}]}
Stats
Project-level counters, shown on the dashboard overview.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectId | string | Optional | - | Target project id. |
bashcurl "https://cohorly-service.velloalabs.com/api/stats?projectId=1" \-H "Authorization: Bearer $API_KEY"
json{"events": 128340,"users": 812,"profiles": 790,"event_names": 34,"events_today": 1204,"sessions": 96}
Status (no auth)
Public health endpoints backing the status page(opens in new tab) - no Bearer key or project token required.
Components
Six components are monitored independently. id is the value used in every
request and response below.
| id | name | group |
|---|---|---|
api | API | Core Platform |
db | Database | Core Platform |
ingestion | Event Ingestion | Core Platform |
dashboard | Dashboard | Web |
docs | Documentation | Web |
status | Status Page | Web |
Each probe target is opt-in on the server. A component that has no probe
configured is simply absent from components[] - it is never fabricated as
healthy, and never counted into any uptime number.
A component's status is resolved by checking these rules in order - the
first match wins:
| order | status | condition |
|---|---|---|
| 1 | unknown | No check recorded in the last 5 minutes (or ever). Rendered as "no data", not as an outage. |
| 2 | maintenance | An in_progress maintenance window covers this component. |
| 3 | degraded | An open incident with minor impact covers this component. |
| 3 | down | An open incident with major/critical impact covers this component (none impact never overrides). |
| 4 | operational | None of the above, and the latest check was ok. |
| 4 | down | None of the above, and the latest check failed. |
Current health snapshot: overall ok/db, every monitored component, active incidents, and scheduled maintenance.
active_incidents holds every kind: "incident" row whose status is not
resolved. scheduled_maintenance holds every kind: "maintenance" row
whose status is not completed. Both are Incident[] - see the shape and
status enums under Incidents below.
History
Daily uptime aggregates for one component. The server records a health check every 60 seconds and keeps 90 days of history. Unchanged shape - existing integrations keep working.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
days | integer | Optional | 90 | Clamped to 1-90. |
component | string | Optional | db | One of the component ids above. Defaults to db, which is exactly today's meaning. An unknown id returns 400. |
Daily uptime aggregates for every monitored component in one call - what the status page itself uses.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
days | integer | Optional | 90 | Clamped to 1-90. |
A day with no recorded checks is omitted from that component's array rather
than reported as 0. Only components with a probe configured appear as keys
in components.
Incidents
Incident and maintenance history, newest first.
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
days | integer | Optional | 90 | Clamped to 1-365. Every unresolved incident and every open maintenance window is included regardless of age; resolved/completed ones are included only if they fall inside the window. |
updates is oldest-first. status is one of two enums depending on kind:
| kind | status values |
|---|---|
incident | investigating -> identified -> monitoring -> resolved |
maintenance | scheduled -> in_progress -> completed |
impact is none | minor | major | critical and only applies to
incidents (none never overrides a component's status; minor degrades it,
major/critical mark it down - see the status table above). resolved_at
is set automatically when status becomes resolved or completed.
Creating and updating incidents is a superadmin-only operation performed from the backoffice, not documented here.
bashcurl https://cohorly-service.velloalabs.com/status
json{"ok": true,"db": true,"uptime_seconds": 128340,"latest": { "checked_at": "2026-07-31T12:00:00.000Z", "ok": true, "latency_ms": 42 },"components": [{"id": "api","name": "API","group": "Core Platform","status": "operational","latest": { "checked_at": "2026-07-31T12:00:00.000Z", "ok": true, "latency_ms": 11 },"uptime_30d": 99.99,"uptime_90d": 99.97},{"id": "db","name": "Database","group": "Core Platform","status": "operational","latest": { "checked_at": "2026-07-31T12:00:00.000Z", "ok": true, "latency_ms": 42 },"uptime_30d": 99.98,"uptime_90d": 99.95},{"id": "dashboard","name": "Dashboard","group": "Web","status": "unknown","latest": null,"uptime_30d": null,"uptime_90d": null}],"active_incidents": [],"scheduled_maintenance": []}
bashcurl "https://cohorly-service.velloalabs.com/status/history?days=30&component=db"
json[{ "date": "2026-07-30", "total": 1440, "ok_count": 1439, "uptime_pct": 99.93, "avg_latency_ms": 38.2 }]
bashcurl "https://cohorly-service.velloalabs.com/status/history/all?days=30"
json{"days": 30,"components": {"api": [{ "date": "2026-07-30", "total": 1440, "ok_count": 1440, "uptime_pct": 100, "avg_latency_ms": 12.4 }],"db": [{ "date": "2026-07-30", "total": 1440, "ok_count": 1439, "uptime_pct": 99.93, "avg_latency_ms": 38.2 }]}}
bashcurl "https://cohorly-service.velloalabs.com/status/incidents?days=90"
json{"incidents": [{"id": 42,"kind": "incident","title": "Elevated ingestion latency","status": "resolved","impact": "minor","components": ["ingestion"],"started_at": "2026-07-28T09:15:00.000Z","resolved_at": "2026-07-28T10:02:00.000Z","scheduled_start": null,"scheduled_end": null,"updates": [{ "id": 101, "status": "investigating", "body": "Investigating elevated /track latency.", "created_at": "2026-07-28T09:15:00.000Z" },{ "id": 102, "status": "identified", "body": "Root cause is a slow query in the ingestion path.", "created_at": "2026-07-28T09:40:00.000Z" },{ "id": 103, "status": "resolved", "body": "Fix deployed, latency back to normal.", "created_at": "2026-07-28T10:02:00.000Z" }]},{"id": 43,"kind": "maintenance","title": "Database upgrade","status": "scheduled","impact": "none","components": ["db"],"started_at": "2026-08-01T00:00:00.000Z","resolved_at": null,"scheduled_start": "2026-08-10T02:00:00.000Z","scheduled_end": "2026-08-10T03:00:00.000Z","updates": []}]}