Issues
Issue tracking API — list, view, update, merge issues and manage comments.
Manage issues — errors automatically detected and grouped from ingested events.
GET /v1/projects/:projectId/issues
List issues for a project. Results are ordered by most recently seen.
Auth required: Yes (issues:read permission or JWT)
Query parameters
| Parameter | Type | Description |
|---|---|---|
status | string | Filter by status: new, in_progress, resolved, silenced, regressed, snoozed. |
app_id | string | Filter to a specific app. |
is_dev | string | Filter by dev mode: true or false. Takes precedence over data_mode. |
data_mode | string | production, development, or all (default when omitted). |
cursor | string | Cursor from previous response for pagination. |
limit | number | Items per page (1-200, default 50). |
Response
{
"issues": [
{
"id": "uuid",
"app_id": "uuid",
"project_id": "uuid",
"status": "new",
"title": "Connection refused",
"source_module": "NetworkService",
"is_dev": false,
"occurrence_count": 42,
"unique_user_count": 15,
"resolved_at_version": null,
"first_seen_sdk_version": "0.1.0",
"last_seen_sdk_version": "0.1.2",
"first_seen_at": "2024-01-15T10:00:00.000Z",
"last_seen_at": "2024-01-15T14:30:00.000Z",
"last_notified_at": "2024-01-15T13:00:00.000Z",
"snoozed_at": null,
"created_at": "2024-01-15T10:00:00.000Z",
"updated_at": "2024-01-15T14:30:00.000Z",
"fingerprints": ["a1b2c3..."],
"app_name": "iOS App"
}
],
"cursor": "uuid-or-null",
"has_more": false
}GET /v1/projects/:projectId/issues/:issueId
Get full issue details including paginated occurrences, comments, and fingerprints.
Auth required: Yes (issues:read)
Query parameters
| Parameter | Type | Description |
|---|---|---|
occurrence_cursor | string | Cursor for occurrence pagination. |
occurrence_limit | number | Max occurrences per page (1-200, default 50). |
Response
Extends the list response with:
{
"occurrences": [
{
"id": "uuid",
"issue_id": "uuid",
"session_id": "uuid",
"user_id": "user123",
"app_version": "2.1.0",
"sdk_name": "owlmetry-swift",
"sdk_version": "0.1.2",
"environment": "ios",
"event_id": "uuid",
"country_code": "US",
"timestamp": "2024-01-15T14:30:00.000Z",
"created_at": "2024-01-15T14:30:01.000Z"
}
],
"occurrence_cursor": "uuid-or-null",
"occurrence_has_more": false,
"comments": [
{
"id": "uuid",
"issue_id": "uuid",
"author_type": "user",
"author_id": "uuid",
"author_name": "Jane Doe",
"body": "Investigating root cause...",
"created_at": "2024-01-15T15:00:00.000Z",
"updated_at": "2024-01-15T15:00:00.000Z"
}
],
"attachments": [
{
"id": "uuid",
"event_id": "uuid",
"original_filename": "crash.log",
"content_type": "text/plain",
"size_bytes": 2048,
"uploaded_at": "2024-01-15T14:30:02.000Z",
"created_at": "2024-01-15T14:30:01.000Z"
}
]
}The attachments array contains up to 100 non-deleted attachments associated with the issue (most recent first). For pagination across all attachments linked to an issue, use the /v1/attachments?issue_id=:issueId endpoint.
PATCH /v1/projects/:projectId/issues/:issueId
Update issue status. Validates status transitions.
Auth required: Yes (issues:write)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
status | string | Yes | Target status: new, in_progress, resolved, silenced, snoozed. Note: regressed is set automatically by the scan job, and snoozed → new is also a job-driven transition (the scan flips a snoozed issue back to new on its next occurrence). |
resolved_at_version | string | When status is resolved | App version where the fix was applied. Required when resolving — powers regression detection. If you don't have a fix version, use silenced (known issue you don't want to hear about again) or snoozed (suspected one-off — auto-reopens on next occurrence). Cleared automatically when transitioning back to new or in_progress. |
Valid status transitions
| From | Allowed targets |
|---|---|
new | in_progress, resolved, silenced, snoozed |
in_progress | new, resolved, silenced, snoozed |
resolved | new, silenced, snoozed |
regressed | in_progress, resolved, silenced, snoozed |
silenced | new, in_progress, resolved, snoozed |
snoozed | new, in_progress, resolved, silenced |
Returns 400 if the transition is not allowed, or if status=resolved is sent without a non-empty resolved_at_version.
snoozed_at is set to the server clock when the issue transitions into snoozed, and cleared on any transition out (including the automatic snoozed → new transition fired by the issue-scan job on the next occurrence). The auto-revert also re-fires the same issue.new push that brand-new prod issues trigger.
POST /v1/projects/:projectId/issues/:issueId/merge
Merge a source issue into the target issue. Moves all fingerprints, occurrences (deduplicated by session), and comments to the target. Deletes the source.
Auth required: Yes (issues:write)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
source_issue_id | string | Yes | The issue to merge from (will be deleted). |
Both issues must belong to the same project. Returns 400 if merging into itself.
GET /v1/projects/:projectId/issues/:issueId/comments
List comments on an issue in chronological order. Soft-deleted comments are excluded.
Auth required: Yes (issues:read)
POST /v1/projects/:projectId/issues/:issueId/comments
Add a comment to an issue. Author is resolved from auth context (user JWT or agent API key).
Auth required: Yes (issues:write)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
body | string | Yes | Comment text. Markdown supported. |
Returns 201 with the created comment.
PATCH /v1/projects/:projectId/issues/:issueId/comments/:commentId
Edit a comment. Only the original author can edit.
Auth required: Yes (issues:write)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
body | string | Yes | Updated comment text. |
Returns 403 if the authenticated user/agent is not the original author.
DELETE /v1/projects/:projectId/issues/:issueId/comments/:commentId
Soft-delete a comment. The original author or a team admin/owner can delete.
Auth required: Yes (issues:write)
Returns { "deleted": true }.
GET /v1/issues
Team-level cross-project issue listing. Returns issues across all accessible teams (or a specific team via team_id). Mirrors the /v1/events pattern. Each issue is returned with a project_name in addition to the per-project response fields.
Auth required: Yes (issues:read permission or JWT)
Query parameters
| Parameter | Type | Description |
|---|---|---|
team_id | string | Filter to a specific team. |
project_id | string | Filter to a specific project. |
status | string | Filter by status: new, in_progress, resolved, silenced, regressed, snoozed. |
app_id | string | Filter to a specific app. |
is_dev | string | Filter by dev mode: true or false. |
data_mode | string | production (default), development, or all. |
cursor | string | Cursor from previous response. |
limit | number | Items per page (1-200, default 50). |
Response
Same shape as GET /v1/projects/:projectId/issues, but each issue also includes a project_name field.
