Skip to content

HTTP API

HTTP API

The dashboard pages this package adds already carry the common decisions as a row menu. This is the same surface, for when you want your own screen — or something the menu does not offer, like assigning an owner.

Everything is mounted beside the dashboard's own API, under its path, middleware and throttle — so the gate that guards the dashboard guards these, and there is no second authorization to wire up.

GET  {path}/api/v2/insights/issues[?status=open]
POST {path}/api/v2/insights/issues/{fingerprint}
GET  {path}/api/v2/insights/incidents
POST {path}/api/v2/insights/incidents/{signature}

{path} is telemetry-ui.path, so by default /telemetry-ui/api/v2/insights/issues.

Authorization

Reading takes viewTelemetryUi, the dashboard's own ability. Changing anything takes manageTelemetryUi, checked in the controller and never trusted to the client — a viewer who can see an issue cannot resolve it.

A refusal is the dashboard's error shape:

{"error": {"type": "forbidden", "message": "You are not authorized to change issues."}}

with not_found (404) and invalid (422) for the other two ways a request can be wrong.

Changing an issue

POST /telemetry-ui/api/v2/insights/issues/aaaa00000001
Content-Type: application/json

{"action": "resolve", "release": "v2.4.1", "by": "sylvester"}
action Extra fields
resolve release, by
reopen —
ignore —
snooze until (e.g. "3 days"; a day when omitted)
assign to

The response carries the issue as the list returns it, with status already the effective one — a lapsed snooze reads as open, here as everywhere else.

Changing an incident

POST /telemetry-ui/api/v2/insights/incidents/abc123def456

{"action": "acknowledge", "by": "sylvester"}

acknowledge, resolve or reopen. Acknowledging is the point of persisting incidents at all: it is how a team says someone is on this without muting the errors underneath.

Shapes

An issue:

{
  "fingerprint": "aaaa00000001",
  "status": "open",
  "type": "RedisException",
  "message": "Connection refused",
  "service": "checkout",
  "assignee": null,
  "lastSeen": "2026-09-26T08:14:02+00:00",
  "firstRecorded": "2026-09-24T02:14:55+00:00",
  "snoozedUntil": null,
  "resolvedAt": null,
  "resolvedIn": null
}

An incident, whose cause is null when none was established:

{
  "signature": "abc123def456",
  "status": "open",
  "title": "redis cache-1:6379 — 9 error groups affected",
  "onsetAt": "2026-09-24T02:14:00+00:00",
  "occurrences": 412,
  "groupCount": 9,
  "fingerprints": ["aaaa00000001"],
  "services": ["checkout"],
  "cause": {
    "kind": "dependency",
    "label": "redis cache-1:6379",
    "evidence": "100% of the affected groups called this cache, and the call failed in 9 of 9 traces inspected.",
    "confidence": "high",
    "traceId": "4458d523d54e5a50"
  },
  "acknowledgedAt": null,
  "acknowledgedBy": null,
  "resolvedAt": null
}

Headless

These routes are part of the soft half: they come from the dashboard's route group, so an app running TELEMETRY_UI_ENABLED=false has no HTTP surface from this package either. Use the IssueActions service or the artisan commands there.