Issues
/api/v1/issuesIssues in the active organization, paginated.
Default view (no status param) is a work queue, not an archive:
ignored issues are excluded. Pass ?status=ignored explicitly to see
them, or ?status=any (#833 review) for every status at once —
the console's "All" built-in view sends this rather than reusing the
omitted-param default, which would silently drop ignored issues from
a view labelled "All".
from/to (#832) filter on last_seen_at, so an issue first seen
long ago but active within the window still shows up. Neither is
required, and omitting both means no time filter — the console always
sends a resolved window (a bounded default, per ADR-0004), but a
direct API caller that sends neither gets the same unbounded result
the endpoint always returned.
assignee_type='me' (#833) resolves to the CALLER's own id from
current_user, exactly as get_current_user derived it from the
session JWT — the query string never carries an id for this case, so a
shared ?assignee_type=me link cannot be repointed at someone else by
editing the URL, and it stays correct for whoever opens it. 'user'/
'team' require assignee_id (400 otherwise); 'unassigned' ignores
it.
Authorization
HTTPBearer In: header
Query Parameters
Page number
1 <= value1Items per page
1 <= value <= 10020Filter by status. Omitted = default view: excludes 'ignored', includes everything else (a regressed issue's status is already back to 'unresolved', so it needs no special case). 'any' (#833) means literally every status, 'ignored' included — the one request 'omitted' cannot make.
Filter by service
Filter to issues with (true) or without (false) a regression history
Window start (inclusive), filtered on last_seen_at. Matches GET /services/{name}/signals' range convention — a real ISO instant, not a relative expression (the console resolves 'now-7d' etc. client-side before sending it). Omitted = open start.
Window end (inclusive), filtered on last_seen_at. Omitted = open end. Omitting both from and to applies no time filter at all — the endpoint's pre-#832 'all time' behavior, unchanged for a caller that sends neither.
Filter by assignee: 'user' or 'team' (with assignee_id), 'me' (resolved from the session — never a client-supplied id), or 'unassigned'
Required when assignee_type is 'user' or 'team'; ignored otherwise
Case-insensitive substring match over title and culprit (#834, the filter language's 'text ~ ...' predicate). Omitted applies no text filter. LIKE wildcards ('%', '_') in the value are matched literally, not as patterns.
Sort field
"last_seen_at"Value in
- "last_seen_at"
- "total_count"
Sort order
^(asc|desc)$"desc"Response Body
application/json
application/json
curl -X GET "https://example.com/api/v1/issues"{ "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "fingerprint": "string", "fingerprint_version": "string", "title": "string", "culprit": "string", "first_seen_at": "2019-08-24T14:15:22Z", "last_seen_at": "2019-08-24T14:15:22Z", "status": "unresolved", "resolved_at": "2019-08-24T14:15:22Z", "assignee_type": "user", "assignee_id": "e209ca2d-190b-4818-b659-67d4ef4f1ce8", "assigned_at": "2019-08-24T14:15:22Z", "assigned_by": "dd7cba77-7080-4b0e-9a94-fdfd1232f6b4", "total_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z", "deployment_id": "6ef0ac85-9892-4664-a2a5-58bf2af5a8a6", "attribution_offset_seconds": 0, "is_regression": true, "occurrence_series": [ { "bucket_start": "2019-08-24T14:15:22Z", "bucket_end": "2019-08-24T14:15:22Z", "count": 0 } ] } ], "total": 0, "page": 0, "per_page": 0}/api/v1/issues/bulk-transition"Select all N matching this filter" (#839, epic console-issues-ux) —
sets to_status on every issue the SAME filter list_issues accepts
matches, in one server-side write. Editor-or-above, same gate as
patch_issue's single-issue transition this fans out.
Takes the filter, never a list of ids (#839's problem statement: fanning
a "resolve everything matching this filter" action out as N client-side
PATCHes means paging the whole matched set into the browser first to
collect ids — the exact cost this endpoint exists to avoid). status/
service_id/regression/from/to/assignee_type/assignee_id/
text are identical in name and meaning to list_issues's own query
parameters — see that route's docstring for the exact semantics — so a
console caller builds this body from the same IssuesFilter state that
already drives the list view.
Bounded at app.services.issue_service.BULK_TRANSITION_LIMIT: a filter
matching more issues than that is refused outright with a 422 naming the
actual count, and NOTHING is written — never applied to only the first
BULK_TRANSITION_LIMIT matches, which would be a silent truncation of
exactly the kind #839 rules out. The response's affected_count is the
real number of rows the write touched, not an assumption equal to
whatever the pre-write filter count was.
Authorization
HTTPBearer In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
POST /api/v1/issues/bulk-transition body (#839, epic
console-issues-ux) — "select everything matching the current filter,
across pages" resolved/ignored/unresolved in one write.
Carries the FILTER, never a list of ids — sending ids would re-introduce
the paging-the-whole-result-set-into-the-browser problem this endpoint
exists to avoid. Every field below except to_status is the identical
name and meaning GET /api/v1/issues already gives its own query
parameters (list_issues's own docstring has the exact semantics of
status/'any', from/to, assignee_type/assignee_id, and text)
— deliberately not renamed, so a console caller building this body from
the SAME IssuesFilter state that drives the list view has nothing to
translate.
to_status is the one field with no read-side counterpart: the target
status every matched issue is set to, same three values IssuePatchRequest .status accepts (never 'any' — that is a filter-only value, meaningless
as something to set an issue TO).
Response Body
application/json
application/json
curl -X POST "https://example.com/api/v1/issues/bulk-transition" \ -H "Content-Type: application/json" \ -d '{ "to_status": "unresolved" }'{ "affected_count": 0}/api/v1/issues/{issue_id}One issue: both counts, its sample events, and its regression
history. 404s if issue_id does not exist in this organization —
scoped in the query itself, so an id belonging to another tenant is
indistinguishable from one that does not exist at all.
Authorization
HTTPBearer In: header
Path Parameters
uuidResponse Body
application/json
application/json
curl -X GET "https://example.com/api/v1/issues/497f6eca-6276-4993-bfeb-53cbbbba6f08"{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "fingerprint": "string", "fingerprint_version": "string", "title": "string", "culprit": "string", "first_seen_at": "2019-08-24T14:15:22Z", "last_seen_at": "2019-08-24T14:15:22Z", "status": "unresolved", "resolved_at": "2019-08-24T14:15:22Z", "assignee_type": "user", "assignee_id": "e209ca2d-190b-4818-b659-67d4ef4f1ce8", "assigned_at": "2019-08-24T14:15:22Z", "assigned_by": "dd7cba77-7080-4b0e-9a94-fdfd1232f6b4", "total_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z", "deployment_id": "6ef0ac85-9892-4664-a2a5-58bf2af5a8a6", "attribution_offset_seconds": 0, "in_retention_count": 0, "samples": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "occurred_at": "2019-08-24T14:15:22Z", "signal_type": "log", "body": "string", "span_name": "string", "severity": "string", "status": "string", "attributes": {}, "trace_id": "string", "span_id": "string", "trace_link": { "available": true, "reason": "missing" } } ], "regressions": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "resolved_at": "2019-08-24T14:15:22Z", "regressed_at": "2019-08-24T14:15:22Z", "deployment_id": "6ef0ac85-9892-4664-a2a5-58bf2af5a8a6", "attribution_offset_seconds": 0, "deployment": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "version": "string", "commit_sha": "string", "started_at": "2019-08-24T14:15:22Z", "status": "string" } } ], "occurrence_series": [ { "bucket_start": "2019-08-24T14:15:22Z", "bucket_end": "2019-08-24T14:15:22Z", "count": 0 } ], "pattern_hash": "string", "deployment": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "version": "string", "commit_sha": "string", "started_at": "2019-08-24T14:15:22Z", "status": "string" }}/api/v1/issues/{issue_id}Status transitions (resolve/ignore/unresolve) and assignment, both optional so a caller may send either or both in one request.
status: sets Issue.status directly. Setting it to 'resolved'
stamps resolved_at = now(); any other value clears it, matching
every non-resolved issue's shape elsewhere in this schema
(test_issue_model.py's TestIssueSchema). This is a human-driven
transition, not an occurrence arriving — it does NOT go through
app.services.issue_regression_service.record_occurrence (that path
is for #570's derivation to call when a signal reopens a resolved
issue) and does not create an IssueRegression row.
assignee: omitted leaves assignment untouched; null unassigns;
an object assigns to that user or team, validated by
app.services.assignment_service.validate_assignee — 400 if
assignee_id does not resolve to a live user or team in this org.
Authorization
HTTPBearer In: header
Path Parameters
uuidRequest Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
PATCH /api/v1/issues/{id} body — status transitions and
assignment, both optional so a caller can send either or both.
assignee follows the standard partial-update convention: omitted
means "leave assignment alone", an explicit null means "unassign",
and an object means "assign to this user or team". The route
distinguishes omitted from explicit-null via model_fields_set
(exclude_unset=True), the same technique
ServiceCatalogService.update_annotations uses.
Response Body
application/json
application/json
curl -X PATCH "https://example.com/api/v1/issues/497f6eca-6276-4993-bfeb-53cbbbba6f08" \ -H "Content-Type: application/json" \ -d '{}'{ "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "org_id": "a40f5d1f-d889-42e9-94ea-b9b33585fc6b", "service_id": "641e839f-864e-4cce-98f9-40f6cbb3e9e0", "fingerprint": "string", "fingerprint_version": "string", "title": "string", "culprit": "string", "first_seen_at": "2019-08-24T14:15:22Z", "last_seen_at": "2019-08-24T14:15:22Z", "status": "unresolved", "resolved_at": "2019-08-24T14:15:22Z", "assignee_type": "user", "assignee_id": "e209ca2d-190b-4818-b659-67d4ef4f1ce8", "assigned_at": "2019-08-24T14:15:22Z", "assigned_by": "dd7cba77-7080-4b0e-9a94-fdfd1232f6b4", "total_count": 0, "created_at": "2019-08-24T14:15:22Z", "updated_at": "2019-08-24T14:15:22Z", "deployment_id": "6ef0ac85-9892-4664-a2a5-58bf2af5a8a6", "attribution_offset_seconds": 0}/api/v1/issues/{issue_id}/related-incidentsIncidents on this issue's service with an overlapping activity
window (#838) — see app/services/issue_incident_correlation.py for
the relation rule. 404s the same way get_issue does: not found in
this org reads the same as not found at all.
Authorization
HTTPBearer In: header
Path Parameters
uuidResponse Body
application/json
application/json
curl -X GET "https://example.com/api/v1/issues/497f6eca-6276-4993-bfeb-53cbbbba6f08/related-incidents"{ "available": true, "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "title": "string", "status": "string", "severity": "string", "started_at": "2019-08-24T14:15:22Z", "resolved_at": "2019-08-24T14:15:22Z" } ], "total": 0}