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.

bash
curl https://cohorly-service.velloalabs.com/api/projects \
-H "Authorization: Bearer $API_KEY"

Projects

GET/api/projects

List projects. A superadmin credential sees every project across every org; a user credential sees only their own org's.

POST/api/projects

Create a project. Creates in the caller's org (superadmin creates in the bootstrap org).

NameTypeRequiredDefaultDescription
namestringRequired-

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/api/projects/{id}

Delete a project and all of its data. Requires the org owner role (or superadmin).

NameTypeRequiredDefaultDescription
idintegerRequired-

Path parameter - the project id.

bash
curl 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
}
]
bash
curl -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
}
bash
curl -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.

GET/api/events

Raw event stream, newest first.

NameTypeRequiredDefaultDescription
projectIdstringOptional-

Target project id. Defaults to the org's oldest project (or the legacy default project for a superadmin credential).

limitintegerOptional100

Max 1000.

eventstringOptional-

Filter to one event name. Applies lexicon merge aliasing (matches the canonical event plus its merged children).

distinct_idstringOptional-

Filter to one user.

fromstring (date)Optional-

YYYY-MM-DD, inclusive.

tostring (date)Optional-

YYYY-MM-DD, inclusive.

searchstringOptional-

Case-insensitive substring match on the event name.

filtersstringOptional-

JSON-encoded PropertyFilter[] (same shape as segmentation). Invalid JSON or shape returns 400.

GET/api/events/names

Distinct event names observed in the project - useful for autocomplete.

NameTypeRequiredDefaultDescription
projectIdstringOptional-

Target project id.

raw"1"Optional-

Bypass lexicon governance (merge collapsing, hidden exclusion) and return observed names untouched.

GET/api/events/properties

Property keys observed on a given event name.

NameTypeRequiredDefaultDescription
projectIdstringOptional-

Target project id.

eventstringRequired-

Event name to inspect.

raw"1"Optional-

Bypass lexicon governance.

bash
curl "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
}
bash
curl "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 }]
bash
curl "https://cohorly-service.velloalabs.com/api/events/properties?projectId=1&event=Signed+Up" \
-H "Authorization: Bearer $API_KEY"
json
["plan", "$city", "$browser"]

Users

GET/api/users

List user profiles.

NameTypeRequiredDefaultDescription
projectIdstringOptional-

Target project id.

limitintegerOptional50

Max 500.

searchstringOptional-

Substring match on distinct_id or the serialized properties.

GET/api/users/{distinctId}

One user's profile plus their last 100 events.

NameTypeRequiredDefaultDescription
projectIdstringOptional-

Target project id.

distinctIdstringRequired-

Path parameter - the user to fetch.

bash
curl "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
}
]
bash
curl "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

GET/api/stats

Project-level counters, shown on the dashboard overview.

NameTypeRequiredDefaultDescription
projectIdstringOptional-

Target project id.

bash
curl "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.

idnamegroup
apiAPICore Platform
dbDatabaseCore Platform
ingestionEvent IngestionCore Platform
dashboardDashboardWeb
docsDocumentationWeb
statusStatus PageWeb

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:

orderstatuscondition
1unknownNo check recorded in the last 5 minutes (or ever). Rendered as "no data", not as an outage.
2maintenanceAn in_progress maintenance window covers this component.
3degradedAn open incident with minor impact covers this component.
3downAn open incident with major/critical impact covers this component (none impact never overrides).
4operationalNone of the above, and the latest check was ok.
4downNone of the above, and the latest check failed.
GET/status

Current health snapshot: overall ok/db, every monitored component, active incidents, and scheduled maintenance.

ok and db keep their original, narrower meaning: API + database health only. A docs, dashboard or status probe going down never flips them - those show up only inside components[]. Existing integrations reading ok/db/latest do not need to change.

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

GET/status/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.

NameTypeRequiredDefaultDescription
daysintegerOptional90

Clamped to 1-90.

componentstringOptionaldb

One of the component ids above. Defaults to db, which is exactly today's meaning. An unknown id returns 400.

GET/status/history/all

Daily uptime aggregates for every monitored component in one call - what the status page itself uses.

NameTypeRequiredDefaultDescription
daysintegerOptional90

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

GET/status/incidents

Incident and maintenance history, newest first.

NameTypeRequiredDefaultDescription
daysintegerOptional90

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:

kindstatus values
incidentinvestigating -> identified -> monitoring -> resolved
maintenancescheduled -> 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.

bash
curl 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": []
}
bash
curl "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 }]
bash
curl "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 }
]
}
}
bash
curl "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": []
}
]
}
PreviousRate limits
NextQueries