Skip to content

Metrics & Analytics API

PandaStack separates two families of project telemetry, both backed by ClickHouse:

  • Metrics — performance and health (requests, errors, latency, bandwidth). The “Metrics” tab.
  • Analytics — audience and traffic (visitors, geography, referrers, devices). The “Analytics” tab.

When ClickHouse is unreachable or unconfigured, responses carry enabled: false and empty data rather than failing. Time-series values are nullable on a densified grid, where null marks a gap (no sample in that bucket).

Concept guides: Metrics and Analytics.

All routes require authentication and are available to any member. Every range-based endpoint takes a ?range query param of type MetricRange: one of 1h, 24h, 7d, 30d (default 24h).


GET /v1/projects/:name/metrics/summary

Performance/health summary tiles for a project.

Query: ?range (default 24h). Response (MetricsSummary):

FieldTypeNotes
rangeMetricRange
enabledbooleanfalse = ClickHouse unreachable.
requestsnumber
errorsnumber
error_ratenumberPercentage, 0–100.
latency_msobject{ p50, p95, p99, avg }.
bandwidth_bytesnumber
unique_visitorsnumber
rpsnumberRequests per second.
Terminal window
curl "https://api.pandastack.io/v1/projects/my-app/metrics/summary?range=24h" \
-H "Authorization: Bearer $PANDASTACK_TOKEN"
{
"success": true,
"data": {
"range": "24h",
"enabled": true,
"requests": 128400,
"errors": 312,
"error_rate": 0.24,
"latency_ms": { "p50": 18, "p95": 140, "p99": 420, "avg": 34 },
"bandwidth_bytes": 8123456789,
"unique_visitors": 9021,
"rps": 1.49
}
}

GET /v1/projects/:name/metrics/timeseries

Query: ?range. Response (MetricsTimeseries): { range, enabled, points: MetricsPoint[] } where each MetricsPoint is { t (ISO), requests, errors, p95, bytes_out } and all values are nullable (null = gap).

GET /v1/projects/:name/metrics/breakdown

Query: ?range, ?limit (default 10). Response (MetricsBreakdown):

FieldTypeNotes
rangeMetricRange
enabledboolean
top_pathsarray{ path, requests, p95 }.
status_codesarray{ status, requests }.
top_countriesarray{ country, requests }.

GET /v1/projects/metrics/sparklines

24-hour request sparklines for every project in the org, in one call (cached ~60s) — used to render the projects list.

Response (ProjectsSparklines): { enabled, projects } where projects is a record keyed by project name, each value { total (24h request total), points: [{ t, requests, errors }] }.

Terminal window
curl https://api.pandastack.io/v1/projects/metrics/sparklines \
-H "Authorization: Bearer $PANDASTACK_TOKEN"

GET /v1/projects/:name/metrics/stream

Server-Sent Events stream that pushes a fresh MetricsSummary roughly every 5 seconds (live KPI tiles).

Because this is SSE, pass the token (and org, for JWTs) as query params: ?range=<range>&access_token=<token>&organization_id=<orgId>. See SSE authentication.

Event: summary, whose data is a MetricsSummary.

Terminal window
curl -N "https://api.pandastack.io/v1/projects/my-app/metrics/stream?range=1h&access_token=$PANDASTACK_TOKEN&organization_id=1907"
event: summary
data: {"range":"1h","enabled":true,"requests":204,"errors":0,"error_rate":0,"latency_ms":{"p50":12,"p95":88,"p99":210,"avg":21},"bandwidth_bytes":10240000,"unique_visitors":31,"rps":0.06}

Audience/traffic insights. Note that analytics carries two boolean flags: enabled (ClickHouse configured at the platform level) and analyticsEnabled (this specific project has analytics turned on).

GET /v1/projects/:name/analytics/summary

Query: ?range. Response (AnalyticsSummary):

FieldTypeNotes
rangeMetricRange
enabledbooleanClickHouse configured platform-wide.
analyticsEnabledbooleanThis project has analytics on.
uniqueVisitorsnumber
totalViewsnumberNon-bot requests.
botViewsnumber
returningVisitorsnumber
viewsPerVisitornumber

GET /v1/projects/:name/analytics/timeseries

Query: ?range. Response (AnalyticsTimeseries): { range, enabled, points: [{ t, visitors, views }] } (values nullable).

GET /v1/projects/:name/analytics/breakdown

Query: ?range, ?limit (default 8). Response (AnalyticsBreakdown):

FieldTypeNotes
rangeMetricRange
enabledboolean
top_countriesDimensionRow[]Each { label, visitors, views }.
top_referrersDimensionRow[]
top_pagesDimensionRow[]
browsersDimensionRow[]
devicesDimensionRow[]
Terminal window
curl "https://api.pandastack.io/v1/projects/my-app/analytics/breakdown?range=7d&limit=8" \
-H "Authorization: Bearer $PANDASTACK_TOKEN"

GET /v1/activity

The org-scoped audit/activity feed — “who did what, when” — cursor-paginated, backed by the shared Events table.

Auth: any member. Query (ActivityQuery):

ParamTypeNotes
cursorstringOpaque cursor from nextCursor.
limitint1–100, default 50.
serviceTypestringFilter by service (e.g. project, database, cronjob).
qstringFree-text match on the event sentence.
projectIdintFilter by project.

Response: paged(ActivityEvent){ items: ActivityEvent[], nextCursor }.

ActivityEvent:

FieldTypeNotes
idnumber
eventstring | nullHuman-readable sentence.
serviceTypeenum | string | nullproject | cronjob | database | edge | monitor | team | organization | managed_app (forward-compatible passthrough).
methodstring | nullPOST | PUT | DELETE.
statusstring | nullsuccess | failed.
organizationIdstring
projectIdnumber | null
deploymentIdnumber | null
actorobject{ userId, name, username, avatarUrl }.
resourceNamestring | null
createdAtstringISO 8601.
Terminal window
curl "https://api.pandastack.io/v1/activity?serviceType=database&limit=25" \
-H "Authorization: Bearer $PANDASTACK_TOKEN"