List issues
Issues across the teams the CALLER IS IN (see listTeams for how that set is decided), ordered by position, then number, then id. Each row OMITS description: descriptions are unbounded markdown and no list renders one, so read it from getIssue instead. Filters combine with AND; q is a case-insensitive title substring match (LIKE wildcards in q are escaped and match literally), or with scope=all a full-text search over titles, descriptions and comments. KEYSET PAGED. Send limit to choose a page size and pass the nextCursor from the previous response to continue. nextCursor is present only while more rows remain, so its absence means the end of the list rather than a truncation the caller was never told about. total counts every row the filters match, not the page, because counts and progress in the UI are drawn from it and a page cannot say how many there are. Cursors are opaque and must not be constructed or parsed by clients: the sort key they encode is free to change. A malformed cursor is a 400 rather than a silent restart, which would re-deliver the whole list. limit defaults to 50. The old behaviour of returning up to 1000 rows in one response is still available by asking for it. An issue in a team the caller is not in is invisible everywhere, not just here: reading one by id is a 404, never a 403, so the response does not confirm that it exists.
View as MarkdownAuthorization
bearer In: header
Query Parameters
Restrict to one team.
uuidPage size. Defaults to 50 and is capped at 1000. A caller that needs the whole set in one response must ask for it explicitly. A full-text search (scope=all) is capped at 50 instead: each row costs a description and its matching comments to check, so a larger value is clamped to 50, and the response reports the size applied.
1 <= value <= 100050Opaque nextCursor from a previous response. Continues after the last row that response returned.
Repeatable. Matches any of the given project ids.
Repeatable. Matches any of the given state ids.
Repeatable. Matches any of the given member ids.
uuiduuidOrdering. manual is the hand-sorted position order and the default. priority puts urgent first and "none" (0) LAST. newest and updated are most-recent-first. due is soonest first with undated issues last. A cursor is only valid for the sort that produced it.
relevance ranks a full-text search, best first, and is a 400 without scope=all and q. Results fall into three tiers: every word in the title or is the issue key, then every word in the title or description, then the rest (a word only in a comment). Within a tier the most recently updated issue comes first. The tiers are judged on the stored text, so an issue whose only description match is inside a link can sit a tier higher than it reads; whether it appears at all is still decided by the exact check. The response reports sort=relevance.
"manual"Value in
- "manual"
- "priority"
- "newest"
- "updated"
- "due"
- "relevance"
Repeatable. 0 none, 1 urgent, 2 high, 3 medium, 4 low.
Repeatable, OR semantics: an issue carrying ANY of these labels matches. An issue matching several is still returned once.
Repeatable. Filters on the state's TYPE rather than its id, because every team names and numbers its own states while the types are shared.
uuidInclusive. Issues with no due date never match. Combine with state_type to express "due soon and still open".
dateWhen true, returns only issues with no assignee, and assignee_id is ignored. A flag rather than a sentinel id, so no real id can ever collide with it.
When true, returns only issues assigned to the caller. Resolved from the request, so a client does not need its own member id. A flag rather than a sentinel id, like unassigned. Combines with assignee_id (both must match) but not with unassigned, which is a 400.
When true, returns only issues in no project, and project_id is ignored.
When true, returns ONLY soft-deleted issues - the Recently Deleted view. Every other view excludes them. An issue is erased for good 30 days after deletion, or sooner via permanentlyDeleteIssue.
When true, returns only issues that have an open blocker: a blocks relation whose source issue is not soft-deleted and whose state type is backlog, unstarted, or started. A completed or canceled blocker does not match. The same rule as blockedByCount.
Case-insensitive. With scope=title (the default) matches the title, or the issue's human key ("ENG-42") when the query looks like one. With scope=all it is a full-text query, see scope.
What q is matched against. title (default) is the title and issue key only, and behaves exactly as it always has.
all also searches descriptions and comments, and each returned issue carries a match saying where and why it matched. q is split into words, every word must be found (in any of the title, description or a comment, not necessarily the same one), and a "quoted phrase" is one word that must appear contiguously. Matching ignores case and markdown syntax: the text of a mention or link is searched, its id and URL are not. At most 5 words, each at least 2 characters, and at most 200 characters overall; anything else is a 400. An unknown scope is a 400 even without q.
In descriptions and comments a word is found by what it starts with: log finds "login", but ogin does not find it. The parts of an address, a path or a name joined by punctuation ("[email protected]", "snake_case") are words of their own. Titles are not matched this way and keep matching any part of a word, so ogin still finds a title that says "login". Only the first 50,000 characters of a text are searched.
A search can be narrowed on a term only if it has a run of at least 3 letters or digits: "login" and "log-in" do, "lo", "ui/ux" and "to-do" do not. A query with even ONE term it cannot narrow is answered by reading every issue in the caller's teams and their comments, whatever the other terms are: "lo login" is not helped by "login". It is valid, but it is held to 1 second instead of 3, and a client should run it when the person asks for it rather than on every keystroke. Past the limit the answer is a 503 if nothing has been found yet, and otherwise what was found, as a 200 with a nextCursor.
A scope=all response has NO total (the cheap count would include candidates the exact check later drops, so it could contradict the results), and its nextCursor is bound to the query: a cursor from one search is a 400 on another, and on an ordinary list.
"title"Value in
- "title"
- "all"
Response Body
application/json
application/json
application/json
application/json
application/json
curl -X GET "https://example.com/v1/issues"{ "issues": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "teamId": "a4ede8ba-7c0a-4485-8763-cbd9b282fbec", "projectId": "5a8591dd-4039-49df-9202-96385ba3eff8", "number": 0, "title": "string", "description": "string", "stateId": "871bb69c-5872-42b2-88b0-72e9da663aaa", "state": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "teamId": "a4ede8ba-7c0a-4485-8763-cbd9b282fbec", "name": "string", "type": "backlog", "color": "string", "position": 0, "description": "string", "canDelete": true }, "priority": 0, "assigneeId": "665a9750-71bd-4b96-bacd-9efa4ae022dd", "assignee": { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "userId": "2c4a230c-5085-4924-a3e1-25fb4fc5965b", "name": "string", "email": "string", "created": "2019-08-24T14:15:22Z" }, "creatorId": "688ebf54-d343-4104-8711-82c2feac534a", "parentId": "70850378-7d3c-4f45-91b7-942d4dfbbd43", "cycleId": "811bdbf8-a42f-4f8c-b62e-39c77332ffe1", "estimate": 0, "position": 0, "dueDate": "2019-08-24", "labels": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "teamId": "a4ede8ba-7c0a-4485-8763-cbd9b282fbec", "name": "string", "color": "string" } ], "childCount": 0, "blockedByCount": 0, "match": { "field": "title", "snippet": [ { "text": "string", "hit": true } ], "commentId": "ee0469af-2fa1-4b7e-b5f1-8e711a95821b", "author": "string", "at": "2019-08-24T14:15:22Z" }, "created": "2019-08-24T14:15:22Z", "modified": "2019-08-24T14:15:22Z", "completedAt": "2019-08-24T14:15:22Z", "mentions": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "name": "string", "email": "string" } ], "following": true, "importedFrom": { "namespace": "string", "key": "string" } } ], "total": 0, "limit": 0, "sort": "string", "nextCursor": "string"}Permanently delete a project
Erases the project row for good. Only valid on a project already in Recently Deleted - anything else, including a live project, is a 404. Issues sitting in Recently Deleted are NOT erased with it: permanent deletion never cascades destruction downward, and issues.project_id is ON DELETE SET NULL, so they simply lose the link and stay independently restorable.
Create an issue
The issue number is per-team incrementing (max(number)+1, computed in a transaction) and position starts equal to the number. State resolution: an explicit stateId must belong to the target team (else 400 "stateId does not belong to that team"); omitted, the team's lowest-position state is used; a team with no states at all is 400 ("no workflow state available; create a state first"). priority defaults to 0 (0 none, 1 urgent, 2 high, 3 medium, 4 low); estimate 0 means "no estimate" and is stored as null. assigneeId must be an org member; projectId/cycleId/parentId must reference rows inside the caller's org (else 400 "invalid …Id"). Records a "created" activity and notifies the assignee (import-mode creates do not notify). The creator and the assignee are seeded as followers of the issue, on imported creates too: seeding notifies nobody, it only decides who hears about later activity. A description containing @[Name](mention:memberId) tokens is processed the same as on a comment (see POST /v1/issues/{id}/comments) — each resolvable mention notifies and follows, even though the description arrived at creation rather than through a later edit.