HTTP routes
Every route below is served on PITOT_ADDR (127.0.0.1:7520 by default;
the image sets :7520).
OTLP shares this listener but uses its own handlers and ingest credential; see
send your first telemetry.
Conditional routes
Section titled “Conditional routes”The table includes every route the binary can register. These routes depend on configuration:
/debug/pprof/*: only whenPITOT_PPROF_ENABLEDis true, which is not the default. Enabling it also turns on mutex and block sampling./mcp,/api/mcp,/api/auth/oauth/*,/oauth/*and/.well-known/*: only whenPITOT_MCP_ENABLEDis true, which is the default./api/agent/*: only whenPITOT_AI_PROVIDERselectsanthropicoropenai, with that provider’s required key. An empty provider disables chat./api/auth/oidc/startand/api/auth/oidc/callback: only inPITOT_AUTH_MODE=oidc. They return 503unavailablewithRetry-Afteruntil provider discovery succeeds.
Everything else is always registered. A path shown with :name or * is the
pattern Echo matches on, not a literal URL.
Interface stability
Section titled “Interface stability”The /api/* routes serve the browser client and can change without migration
paths. MCP is the agent interface. OTLP ingest and
operational endpoints have their own contracts.
Manage alert rules on the Alerts page or through the HTTP API.
Administrators manage ingest tokens on Connect telemetry or with
/api/settings/ingest/tokens.
Errors
Section titled “Errors”Application API errors, including unknown routes and wrong methods, return objects shaped like
{"code":"bad_request","message":"Safe explanation"}. Codes are stable
snake_case identifiers; clients branch on code rather than message text.
Invalid dashboard or panel specs also include problems with field paths,
messages and optional hints. Every error response uses Cache-Control: no-store;
HEAD errors have no body. Server failures return a short, safe message; the
underlying error is logged and never returned.
Default codes by HTTP status:
| Status | Code |
|---|---|
| 400 | bad_request |
| 401 | unauthorized |
| 403 | forbidden |
| 404 | not_found |
| 405 | method_not_allowed |
| 409 | conflict |
| 413 | payload_too_large |
| 415 | unsupported_media_type |
| 422 | unprocessable |
| 429 | rate_limited |
| 500 | internal |
| 502 | bad_gateway |
| 503 | unavailable |
| 504 | timeout |
Other 4xx statuses use bad_request; other 5xx statuses use internal.
Specific conditions use already_current, dashboard_version_not_found,
dashboard_version_conflict, invalid_spec and last_active_administrator.
GET /api/telemetry/schema returns 503 schema_busy with Retry-After when a
new window and namespace cannot start a discovery yet, or when the discovery is
still running after 15 seconds; it keeps running, so a retry finds it cached.
Cached ones are always served. An unknown window is 400 bad_request.
Tool failures carry error: {code, message} inside the tool result.
Panel execution results keep their own status and error fields.
OAuth, OTLP/gRPC, MCP JSON-RPC and AG-UI run errors keep their protocol spelling.
Operational responses at /healthz, /readyz and /metrics keep their bodies.
Roles maps capabilities to roles.
| Method | Path | Requires |
|---|---|---|
GET | / | none |
GET | /* | none |
GET | /.well-known/oauth-authorization-server | protocol handshake |
GET | /.well-known/oauth-protected-resource | protocol handshake |
GET | /.well-known/oauth-protected-resource/mcp | protocol handshake |
POST | /api/agent/runs | agent:run |
GET | /api/agent/threads | agent:run |
DELETE | /api/agent/threads/:id | agent:run |
GET | /api/agent/threads/:id | agent:run |
PATCH | /api/agent/threads/:id | agent:run |
GET | /api/alerting/alerts | telemetry:read |
GET | /api/alerting/email | telemetry:read |
GET | /api/alerting/rules | telemetry:read |
POST | /api/alerting/rules | alerts:manage |
DELETE | /api/alerting/rules/:id | alerts:manage |
PUT | /api/alerting/rules/:id | alerts:manage |
POST | /api/alerting/rules/:id/test | alerts:manage |
GET | /api/alerting/summary | telemetry:read |
POST | /api/annotations/query | telemetry:read |
POST | /api/auth/code/send | none |
POST | /api/auth/code/verify | none |
POST | /api/auth/link/verify | none |
POST | /api/auth/logout | any signed-in user |
GET | /api/auth/me | any signed-in user |
GET | /api/auth/oauth/authorize | any signed-in user |
POST | /api/auth/oauth/authorize | any signed-in user |
GET | /api/auth/oauth/connections | any signed-in user |
POST | /api/auth/oauth/connections/:id/revoke | any signed-in user |
GET | /api/auth/oidc/callback | none |
GET | /api/auth/oidc/start | none |
POST | /api/auth/setup | none |
GET | /api/auth/status | none |
GET | /api/dashboards | dashboards:manage-own |
POST | /api/dashboards | dashboards:manage-own |
DELETE | /api/dashboards/:id | dashboards:manage-own |
GET | /api/dashboards/:id | dashboards:manage-own |
PATCH | /api/dashboards/:id | dashboards:manage-own |
PUT | /api/dashboards/:id | dashboards:manage-own |
GET | /api/dashboards/:id/versions | dashboards:manage-own |
GET | /api/dashboards/:id/versions/:version | dashboards:manage-own |
POST | /api/dashboards/:id/versions/:version/restore | dashboards:manage-own |
POST | /api/fanql/complete | telemetry:read |
POST | /api/fanql/format | telemetry:read |
POST | /api/fanql/parse | telemetry:read |
GET | /api/fanql/reference | telemetry:read |
GET | /api/insights | telemetry:read |
Any | /api/mcp | telemetry:read |
POST | /api/queries/exemplars | telemetry:read |
POST | /api/queries/run | telemetry:read |
POST | /api/queries/variables/resolve | telemetry:read |
GET | /api/settings/ingest | ingest:read-metadata |
GET | /api/settings/ingest/tokens | ingest:manage |
POST | /api/settings/ingest/tokens | ingest:manage |
POST | /api/settings/ingest/tokens/:id/revoke | ingest:manage |
GET | /api/telemetry/schema | telemetry:read |
GET | /api/traces/:id | telemetry:read |
GET | /api/users | users:manage |
POST | /api/users | users:manage |
DELETE | /api/users/:id | users:manage |
PATCH | /api/users/:id | users:manage |
POST | /api/users/:id/access/revoke | users:manage |
PATCH | /api/users/:id/role | users:manage |
PATCH | /api/users/:id/status | users:manage |
GET | /debug/pprof/ | operations:read |
GET | /debug/pprof/:name | operations:read |
GET | /debug/pprof/cmdline | operations:read |
GET | /debug/pprof/profile | operations:read |
GET | /debug/pprof/symbol | operations:read |
GET | /debug/pprof/trace | operations:read |
GET | /healthz | none |
Any | /mcp | protocol handshake |
GET | /metrics | operations:read, or a service credential |
POST | /oauth/register | protocol handshake |
POST | /oauth/token | protocol handshake |
GET | /readyz | none |
GET | /scim/v2/Users | SCIM bearer token, when PITOT_SCIM_TOKEN is set |
POST | /scim/v2/Users | SCIM bearer token, when PITOT_SCIM_TOKEN is set |
GET | /scim/v2/Users/:id | SCIM bearer token, when PITOT_SCIM_TOKEN is set |
PATCH | /scim/v2/Users/:id | SCIM bearer token, when PITOT_SCIM_TOKEN is set |
What the requirements mean
Section titled “What the requirements mean”- none: reachable without a credential.
- any signed-in user: a session, but no particular capability.
- protocol handshake: the OAuth and MCP endpoints, which authenticate as part of their own protocol rather than through the middleware.
- a named capability: the caller’s role must carry it.
- or a service credential: additionally reachable without a browser session, which is how a scraper reaches the metrics endpoint.
Any registers every HTTP method with the same authorization requirement.
GET /* serves the single-page application for browser paths. Unknown /api/*
and OTLP paths return errors.
OTLP overload responses
Section titled “OTLP overload responses”OTLP admission counts protobuf spans, log records or metric points before
converting them into storage rows. Under compaction debt, interactive starvation
(refusals or queue-wait timeouts), or the decoded-byte budget, the entire export
is refused retryably. Panel queueing alone does not trigger ingest throttling.
gRPC responds with RESOURCE_EXHAUSTED and google.rpc.RetryInfo; HTTP responds
with 429 and Retry-After in whole seconds rounded up. The message identifies
the pressure reason. Rate refusals request a one-to-five-second delay; the hard
debt limit requests two seconds. Byte-budget refusals retain their existing
retry delay. Enable exporter retries and honor these delays; clients with
retries disabled can drop refused telemetry. An acknowledgement still means
the accepted export was durably published.
Exemplars and trace detail use a priority read lane with reserved capacity.
Panels and interactive reads have separate bounded queues; a refused read
retains the existing 503 busy response with Retry-After.