A valid request URL is required to generate request examples{
"success": true,
"data": [
{
"id": "containment",
"name": "Containment rate",
"description": "Share of conversations the AI handled without a human transfer.",
"category": "AI & handover",
"unit": "percent",
"unitLabel": "%",
"format": "0.0%",
"agg": "ratio",
"grain": "call",
"dimensions": [
"agent",
"queue",
"channel",
"time"
],
"allowedViz": [
"kpi",
"line"
],
"defaultViz": "kpi",
"priority": 100,
"target": {
"good": 0.8,
"warn": 0.6,
"dir": "up"
},
"requiresCapture": "",
"liveCapable": true,
"hasDrilldown": true
},
{
"id": "topics",
"name": "Topics",
"description": "What callers talk about, clustered by theme.",
"category": "Voice of customer",
"unit": "categorical",
"unitLabel": "",
"format": "#,##0",
"agg": "categorical",
"grain": "call",
"dimensions": [
"agent",
"channel",
"time"
],
"allowedViz": [
"columns",
"table"
],
"defaultViz": "columns",
"priority": 60,
"requiresCapture": "",
"liveCapable": false,
"hasDrilldown": true
}
]
}{
"type": "about:blank",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
]
}{
"type": "about:blank",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
]
}The Observe metric catalog (self-describing registry)
The complete, self-describing metric registry — everything a client (or an LLM holding only an API key + this contract) needs to compose a dashboard WITHOUT any out-of-band knowledge. Each entry names the metric’s unit/format (how to render the number), its agg/grain (how it is computed), the dimensions it accepts as filter lenses, and — critically — its allowedViz (the ONLY visualizations this metric may render as; defaultViz is the natural pick) and its target thresholds.
Two flags gate composition: requiresCapture is non-empty (“coming soon”) when the metric depends on a data-capture pass not yet emitting — such a metric is discoverable but should be shown disabled, not placed live; hasDrilldown says whether GET /metrics/{id}/calls will return the conversations behind the number. A widget’s viz MUST be one of that metric’s allowedViz or the dashboard write is rejected.
This registry is the general, forward path for analytics — the composable engine behind Observe. The bespoke /analytics/* endpoints (getOrgAnalyticsOverview, getOrgAnalyticsByAgent, getOrgAnalyticsTimeseries, getAgentAnalytics) are pre-built, fixed money cards that compute similar numbers; reach for the registry when you want to pick and chart metrics yourself, and for the fixed cards when you just want the ready-made hero numbers.
A valid request URL is required to generate request examples{
"success": true,
"data": [
{
"id": "containment",
"name": "Containment rate",
"description": "Share of conversations the AI handled without a human transfer.",
"category": "AI & handover",
"unit": "percent",
"unitLabel": "%",
"format": "0.0%",
"agg": "ratio",
"grain": "call",
"dimensions": [
"agent",
"queue",
"channel",
"time"
],
"allowedViz": [
"kpi",
"line"
],
"defaultViz": "kpi",
"priority": 100,
"target": {
"good": 0.8,
"warn": 0.6,
"dir": "up"
},
"requiresCapture": "",
"liveCapable": true,
"hasDrilldown": true
},
{
"id": "topics",
"name": "Topics",
"description": "What callers talk about, clustered by theme.",
"category": "Voice of customer",
"unit": "categorical",
"unitLabel": "",
"format": "#,##0",
"agg": "categorical",
"grain": "call",
"dimensions": [
"agent",
"channel",
"time"
],
"allowedViz": [
"columns",
"table"
],
"defaultViz": "columns",
"priority": 60,
"requiresCapture": "",
"liveCapable": false,
"hasDrilldown": true
}
]
}{
"type": "about:blank",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
]
}{
"type": "about:blank",
"title": "<string>",
"status": 123,
"detail": "<string>",
"instance": "<string>",
"code": "<string>",
"errors": [
{
"field": "<string>",
"message": "<string>"
}
]
}Authorizations
Flowyte secret API key (Authorization: Bearer flowyte_sk_live_…). Scope-gated; is scoped to your organization — a key can never reach another tenant. The listed scopes in each operation's apiKey requirement are the scopes that key must hold. The tokenUrl is nominal: keys are minted in the dashboard.