Issue Reports
Org-wide feed of issue reports filed against calls.
Issue reports flag specific calls for quality review. They are created
on a per-call basis via
POST /v1/calls/{call_id}/issue-reports
and can also be filed automatically by call grading
when it detects an issue pattern. This page documents the org-wide feed
— use it to build dashboards and route issues to your QA workflow.
Endpoints
| Method | Path | Description |
|---|---|---|
GET | /v1/issue-reports | List issue reports across all calls (paginated) |
PATCH | /v1/issue-reports | Bulk-update status by trace_id |
PATCH | /v1/issue-reports/{trace_id} | Update one report's status |
Issue report object
{
"id": 4321,
"trace_id": "5f9a...",
"call_id": 987654321,
"agent_id": 12,
"source": "user",
"severity": "warning",
"status": "open",
"title": "Agent paused too long",
"description": "Five-second silence before responding to the main question.",
"what_went_wrong": "",
"suggested_fix": "",
"timestamp_seconds": 48,
"failing_turn_index": null,
"detected_issue_ref": null,
"metadata": {},
"reported_by_id": 7,
"linked_test_cases": [],
"regression_guarded": false,
"created_at": "2026-04-20T18:25:11.002Z",
"updated_at": "2026-04-20T18:25:11.002Z"
}| Field | Type | Description |
|---|---|---|
id | integer | Issue report id |
trace_id | UUID | Stable id for external linking — also the key for status updates |
call_id | integer | Parent call |
agent_id | integer | null | Agent that handled the parent call |
source | string | user (manually filed from the UI / API) or system (automatically filed — e.g. by call grading) |
severity | string | info, warning, or critical |
status | string | open, acknowledged, or resolved |
title | string | Short description, 1–255 chars |
description | string | Free-form body |
what_went_wrong | string | Grader analysis of the failure (system reports) |
suggested_fix | string | Grader-suggested remediation (system reports) |
timestamp_seconds | integer | null | Offset in seconds into the call the issue refers to |
failing_turn_index | integer | null | Transcript turn index where the issue manifested — used by investigations to replay from the right point |
detected_issue_ref | string | null | Free-form id set by grading to correlate recurring patterns |
metadata | object | Free-form bag for your own app data |
reported_by_id | integer | null | User id of the reporter. null when created by the system |
linked_test_cases | array | Test scenarios created from this issue: {id, agent_id, title, source, latest_verdict, created_at} |
regression_guarded | boolean | True when the issue has linked scenarios and every one currently passes |
created_at, updated_at | timestamp | ISO 8601 UTC |
List issue reports
curl 'https://api.thunderphone.com/v1/issue-reports?severity=critical' \
-H "Authorization: Bearer sk_live_YOUR_API_KEY"issues = requests.get(
"https://api.thunderphone.com/v1/issue-reports",
headers={"Authorization": "Bearer sk_live_YOUR_API_KEY"},
params={"severity": "critical"},
).json()Query parameters
| Param | Type | Description |
|---|---|---|
severity | string | Filter: info, warning, critical |
status | string | Filter: open, acknowledged, resolved |
call_id | integer | Filter to a single call |
agent_id | integer | Filter to reports on calls handled by this agent |
start_date | ISO 8601 | Earliest created_at |
end_date | ISO 8601 | Latest created_at |
limit | integer | Page size (default 100, capped at 500) |
offset | integer |
Returns 200 OK with a paginated envelope of
Issue report objects, ordered by severity
(critical → warning → info) and then newest first:
{
"results": [ /* Issue report objects */ ],
"total": 42,
"limit": 100,
"offset": 0
}Update a report's status
Reports move through open → acknowledged → resolved (any
transition is allowed). Both update endpoints accept only status.
Single report
curl -X PATCH https://api.thunderphone.com/v1/issue-reports/5f9a... \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "resolved"}'The path key is the report's trace_id (not the integer id).
Returns 200 OK with the updated
Issue report object, or 404 if no report
with that trace_id exists in your org.
Bulk
curl -X PATCH https://api.thunderphone.com/v1/issue-reports \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"trace_ids": ["5f9a...", "77b1..."],
"status": "acknowledged"
}'| Field | Type | Required | Description |
|---|---|---|---|
trace_ids | array of UUID | yes | 1–500 ids |
status | string | yes | open, acknowledged, or resolved |
{ "updated": 2 }Unknown trace_ids are skipped silently — updated counts the rows
actually changed.
Issue clusters
Reports that share a failure mechanism are grouped into clusters — the rows on the dashboard's Issues page. Each cluster carries a name, a failure-mode description, a fix lane, aggregate counts, and (when one exists) a summary of its latest investigation.
List issue clusters
GET /v1/issue-clusters
Returns { "results": [...], "total": n, "limit": n, "offset": n }. Each
cluster includes fix_lane (prompt, audio, runtime, model, config,
infra, other), severity, call_count, report_count,
investigation_summary, and flagged_at — when the cluster was flagged to
ThunderPhone (platform-side lanes are flagged automatically; so are prompt
issues whose investigation ended without a confirmed fix).
Update a cluster
PATCH /v1/issue-clusters/{cluster_id}
Accepts status (open, acknowledged, resolved) and/or fix_lane with
fix_lane_source. Setting a status cascades to the cluster's reports;
reclassifying onto a platform-side lane flags the cluster to ThunderPhone
automatically.
Escalate a cluster
POST /v1/issue-clusters/{cluster_id}/escalate
Body: { "note": "..." }. Sends the cluster to ThunderPhone with a full
evidence bundle (reports, evidence values, recent investigation results).
Escalating again appends your note to the open escalation. Emits the
issue.escalated webhook.