REST API

Issues

Search, create, edit, comment on, attach to, move, link and import issues.

  • GET /issues (tracker:read): search. Query: project, status (keys of the project's workflow), category (todo, in_progress, done), severity, priority, type, nature (problem, improvement, task: the type's nature, which works in any project) (comma-separated lists), label, assignee (me, none or id), open_only (true), blocked_only (true: only those with the blocked flag), mine (true: only those with the token's person as assignee or QA, like "My tasks" on screen), watching (true: only those they watch), q (free text: code, title, description and comments), query (advanced query, written in Portuguese, e.g. projeto = MOB e status = Aberto e responsavel = eu), saved_filter (the name of a saved filter), created_from and created_to (YYYY-MM-DD), limit (up to 50), offset, sort (code, title, status, severity, assignee or updated), order (asc or desc) and done_last (true: completed ones, group done, at the end, before the requested order). Without sort, most recent first. The API hides nothing by default: without a status filter, completed ones come too. The task list on screen hides completed ones until the person asks to "Show completed" (and then shows them at the end); to reproduce that, use open_only=true or done_last=true. In the MCP, the same open_only and done_last of search_issues. Each issue comes with close_reason (in Closed), blocked and blocked_reason (the blocked flag), retest_failed (failed the last retest and not approved yet), assignee, qa_owner, sprint, release, releases (every delivery as "GOP 1.4.8-ota002", the main one first), module, parent and epic (codes), labels, start_date, due_date, external_id and edit_version (for PATCH and the batch, without opening each issue); include=description,custom_fields adds the description and custom fields.
  • GET /search?q=<text> (tracker:read): "has this happened before?". Hybrid search, by meaning and by words, in issues (with their comments) and, with kinds=issue,ticket, in Help desk tickets (only for agents). issue=<code> instead of q looks for issues similar to that one, without it. project, open_only (true) and limit (up to 30, default 8). Each result has kind, code, title, status_label, open, project, score (0 to 1), similarity (from the vector, when found by meaning), matched_by (text, meaning), likely_duplicate and url; mode is hybrid or text (words only); semantic says whether search by meaning is on for the company: on, indexed (how many items are already in the index; it grows every minute while the index is being built) and, when off, reason (no_vector: search by meaning isn't available on this server; no_key: aqua off, the company's own key or no AI credits). With on true and mode text, search by meaning didn't answer in time or the person went over the limit of searches by meaning. With issue, the search starts from the context card aqua writes for each issue (aqua_context in GET /issues/{ref}). explain (default true; false returns only the search list, faster) makes aqua check each hit against the reference: it drops the ones that only share words and fills in relation (same: the same problem; related: related) and reason (the link in one sentence); explained says whether it checked (without aqua turned on, false and the search list). Before creating an issue, search here to avoid duplicates (see "Has this happened before?" above). In the MCP: search_similar.
  • GET /issues/{code or id} (tracker:read): the issue with status (key, label, category, close_reason in Closed with key and label, and retest_failed_at when it failed the last retest), blocked (since and reason, or null), releases (every delivery, the main one first with primary: true), parent and epic (the parent, or the parent's parent for a subtask), children, sprint, points, estimate, dates, custom fields, labels, links, watchers, comments, history (from/to with the stored values and text, as on screen: names of releases, people and sprints; from_label/to_label when the screen shows from/to), aqua_summary (the last conversation summary aqua made on screen: happened, pending, ball with whose court the ball is in and outdated when there were comments or changes after it; null without a summary), aqua_context (the context card aqua writes on its own, in the background, for "Has this happened before?": summary with the problem in neutral words, area, terms, generated_at and outdated when the issue changed and the card is yet to be redone; null with aqua off or before the first card) and edit_version (for PATCH). ?fields=status,releases returns only those parts (id, code, url and edit_version always): good for checking many issues without fetching comments and history.
  • GET /issues/{code or id}/comments (tracker:read): every comment, each with id, author, text, at, edited_at, deleted (who deleted it and when; the text comes empty), mentions and the replies (replies).
  • POST /issues/{code or id}/comments (tracker:write): comments, {"text": "...", "parent_id": "<id of the comment being replied to>"}. @Nome mentions someone in the project. "attachments": [{"file_name": "report.md", "content_base64": "..."}, {"url": "https://..."}] attaches up to 5 files to the comment (14 MB combined), with the attachment rules below; one bad attachment refuses the whole comment. 201 with the id and the attachments. In the GET, each comment carries its attachments (id, name, type, size_bytes, download_url).
  • GET /issues/{code or id}/evidences (tracker:read): the issue's attachments (evidence), oldest to newest, each with id, name, type, size_bytes, description, comment_id (when it came in a comment) and download_url. GET /evidences/{id} (tracker:read) downloads the file, with the same token (accepts Range). Over the MCP, whose token doesn't work here, get_attachment reads the content: text (md, csv, txt, log, json) and images (png, jpg, webp, gif up to 5 MB); chat attachments too.
  • POST /issues/{code or id}/evidences (tracker:write): attaches a file, three ways: multipart/form-data with the file in the file field (and description and comment_id optional, as text); JSON {"file_name": "review.md", "content_base64": "...", "description": "..."} (accepts the data:...;base64, prefix); or JSON {"url": "https://example.com/screenshot.png"}, which tracker downloads (https and public addresses only, up to 3 redirects and 20 s; the URL isn't stored; the optional file_name changes the name). Formats by the name's extension: png, jpg, jpeg, webp, gif, mp4, mov, pdf, json, txt, log, md, csv, zip; up to 15 MB per file and 60 files per hour per person. comment_id puts the file under one of your comments on the issue. PO/PM, QA, dev or admin (403 for others). 201 with attachment (as in the GET). There's no pre-signed URL: the bucket is private and every file goes through tracker, which checks the format and size. DELETE /issues/{code or id}/evidences/{id} removes it (the uploader or a project admin; the file of an approval version stays). In the MCP: attach_file, remove_attachment and attachments in add_comment; attachments show up in get_issue (evidences).
  • PATCH /issues/{code or id}/comments/{id} (tracker:write): fixes the text, {"text": "..."}. Only the author (403 for others); the previous text is kept for the admin. DELETE on the same address deletes it: the comment stays in place, without the text (the author or a company admin).
  • GET /issues/{code or id}/history (tracker:read): the full history, most recent first (limit up to 200, offset), with total and each event with at, by, action, field, text and, when present, from and to already with names.
  • POST /issues/{code or id}/move (tracker:write): takes the issue to another project in the same organization, {"project": "CHG", "confirm": true}. Without confirm, it only returns the preview (moved: false, warnings about what has no equivalent in the target, subtasks that go along); with confirm: true, it moves and returns the new code (code) and the old one (previous_code), which still finds the issue. 409 if the issue changed in the meantime: read it again and repeat. Requires editing the issue and creating issues in the target.
  • POST /issues/{code or id}/links (tracker:write): links to another issue, {"target": "MOB-0007", "type": "blocks"} (blocks, relates_to, the default, or duplicates). Requires editing the issue. 201 with the issue's links (links, each with id). DELETE /issues/{ref}/links/{id} removes a link.
  • GET /issues/{code or id}/proofs (tracker:read): proof approval (Design). The versions sent, newest to oldest, with status (pending, approved, changes_requested, superseded), note, decision with comment and the file (download_url). pending is the id of the version awaiting a decision.
  • POST /issues/{code or id}/proofs (tracker:write): sends the next version, as multipart/form-data with file and an optional note (same formats and size as evidence). The one awaiting a decision is superseded. PO/PM, QA, dev or admin. 201 with version and the versions.
  • POST /issues/{code or id}/proofs/{id}/decision (tracker:write): {"decision": "approve"} or {"decision": "changes", "feedback": "what to change"}. PO/PM, QA, admin or the project's client (stakeholder). With the Design workflow, sending moves the issue to In approval, approving to Approved and requesting changes to Revisions. 422 when the version was already decided or superseded.
  • GET /issues/{code or id}/watchers (tracker:read): who watches the issue (gets status and new comment notifications), with watching for the token's person. POST adds and DELETE removes (tracker:write): with nothing, the person themselves; {"person": "[email protected]"} in the POST or ?person=... in the DELETE for another person in the project, which requires editing the issue. The response has person (who was added or removed), watching and watchers. GET /issues/{ref} also returns watchers.
  • POST /issues/{code or id}/status (tracker:write): moves the issue to another status, {"status": "<key>"}. The project's workflow and the person's role in it apply (422 when the transition isn't allowed). For closed (Closed, QA template), also send close_reason: duplicated, cancelled, not_reproduced or wont_fix; with the issue already in closed, the same request changes only the reason.
  • POST /issues/{code or id}/block (tracker:write): flags the issue as blocked, {"reason": "what's in the way"} (optional; sending it again changes the reason). The flag works in any status and goes away on its own when the issue is completed. DELETE on the same address removes it. Every project role except stakeholder; a completed issue can't be blocked (422). Returns blocked (since, reason) or null. In the MCP: block_issue.
  • DELETE /issues/{code or id} (tracker:write): deletes the issue (admin or the project's PO/PM; 403 for other roles). It disappears from lists, search and the API and can be restored for 30 days (on screen, in Issues → Deleted, or with POST /issues/{ref}/restore). An issue with issues inside it (epic, subtasks) isn't deleted (422).
  • POST /issues/{code or id}/restore (tracker:write): restores an issue deleted in the last 30 days, with comments, evidence and history. Admin or the project's PO/PM. GET /issues/deleted (tracker:read, optional project) lists the ones the person can restore (the 200 most recent), with restore_until. After 30 days restoring returns 422.
  • POST /issues/{code or id}/duplicate (tracker:write): creates a copy in the same project, like Duplicate on screen (content, classification, parent, points, fields and labels; no comments, evidence, links, people, sprint, release or technical notes). 201 with the copy's code. Requires creating issues in the project.
  • POST /issues (tracker:write): creates an issue. 201 when it creates; 200 when one with the same external_id already existed in the project. assignee and qa_owner (me, id, e-mail or name of someone in the project) assign at creation: PO/PM and admins assign anyone, devs take it as assignee and QA as QA owner (403 otherwise; 422 when the person isn't in the project, without creating the issue). Devs create only subtask-level types, with the parent. With ?similar=true, the created issue's response also has similar: the similar ones aqua confirmed (code, title, status_label, open, relation, reason, likely_duplicate, url), to link.
  • PATCH /issues/{code or id} (tracker:write): edits the issue. Only the fields sent change; null clears the value. Accepts the text fields, title, type, severity, priority, module, custom_fields (only the keys sent change; a key that doesn't exist in the project is refused), assignee and qa_owner (me, id, e-mail or name of someone in the project), the technical notes (root_cause, fix_notes, fixed_version, fixed_build), parent, story_points, sprint (name or id of an open sprint; null goes back to the backlog), release (the main one: version or id; from another project in the company, "PLT backend-1a2b3c", when the fix ships only there), add_releases/remove_releases (other deliveries of the same fix, including in another project: id, version in the issue's project, "GOP 1.4.8-ota002" or {"project": "GOP", "version": "1.4.8-ota002"}, as a list or a comma-separated text; requires linking releases in both projects) and add_labels/remove_labels. Each group requires the right role in the project (403 when it can't). The groups are saved in sequence: if one fails, the response has applied with the ones already saved. To avoid overwriting someone else's edit, send edit_version (the value read in GET /issues/{ref}): if someone changed the issue after that (fields, people, technical notes, parent, points, sprint, release, labels, estimate or dates; status, comments and hours don't count), nothing is saved and the response is 409 (conflict); read it again and reapply. The success response has the new edit_version.
  • GET /issues/{code or id}/time (tracker:read): estimate, start, due date, recurrence (recurrence and next_occurrence), total logged, remaining and the time entries.
  • POST /issues/{code or id}/time (tracker:write): logs hours worked, {"duration": "1h30", "work_date": "YYYY-MM-DD", "comment": "..."} (or minutes instead of duration; without work_date, today). PO/PM, QA, dev and admin roles.
  • PATCH /issues/{code or id}/plan (tracker:write): {"estimate": "8h", "start_date": "YYYY-MM-DD", "due_date": "YYYY-MM-DD", "recurrence": "monthly"}. An omitted field stays as it is; null clears the value. recurrence (weekly, monthly, quarterly, yearly) makes the issue repeat: when it's completed, the next occurrence is born with start and due date moved forward, the same assignees and labels; time.next_occurrence points to it. Also works in POST /issues and in each item of POST /issues/import; null, "" or "none" removes the recurrence.
  • GET /issues/{code or id}/code (tracker:read): PRs (GitHub), MRs (GitLab) and commits linked to the issue, with id, repository, state (open, draft, merged, closed), branch, author and link.
  • POST /issues/{code or id}/code (tracker:write): links a PR or commit by its link, {"url": "https://github.com/owner/repo/pull/12", "title": "..."} (GitLab MRs or commits too, including self-hosted). Doesn't change the status. 409 when it's already linked (commits by short or full sha). In a connected repository, the webhook later updates the title and state. PO/PM, QA, dev and admin roles.
  • DELETE /issues/{code or id}/code?link_id=<id> (or ?url=<link>, or the same in the JSON body) (tracker:write): unlinks. 404 when it wasn't linked.
  • GET /time (tracker:read): time report. Query: from and to (YYYY-MM-DD; default, the current month), project (prefix, slug or id) and person (me or id); a filter that doesn't match is an error. Totals per person, per project and per issue, and the entries.
  • POST /issues/bulk (tracker:write): the same action on up to 100 issues, {"issues": ["MOB-0012", "MOB-0013"], "action": "status", "value": "done"}. action: status, assignee (PO/PM or admin only; me, id, e-mail or name; none clears), priority, severity, label, unlabel, release (version or id; none clears), watch, unwatch and delete (the last three without value). Each issue follows the rule of the individual action; the response has requested (distinct issues requested), updated and failed (code and error for each one that didn't change). Without value on an action that needs one: 422.
  • POST /issues/batch (tracker:write): a per-issue batch, up to 50, to close out a delivery in one call: {"items": [{"issue": "MOB-0045", "fixed_version": "backend 4e8998ac", "fix_notes": "...", "code_links": ["https://github.com/org/repo/pull/251"], "status": "ready_for_qa"}]}. Each item accepts the fields of PATCH /issues/{ref} (including edit_version), code_links (links, or {url, title}; an already-linked link isn't an error) and status, applied in that order with the rules of the individual calls. An item that fails doesn't stop the others; the response has requested, succeeded, failed and results (per item: ok, code, updated, linked, status and, if it failed, failed_at with issue (not found, or changed after the edit_version), fields, code_links or status, and error; earlier steps stay saved). Without other fields, edit_version protects the links and the status.
  • POST /issues/import (tracker:write): up to 100 issues per request, {"project": "MOB", "issues": [...]} (each item can carry its own project). Item by item: a refused one doesn't undo the others. The response has created, existing, failed and results (index, ok, code, url or error).

Issue fields: project (prefix, slug or id), title (required), type (the type key), severity (S1 to S4, default S3), priority (urgent, high, medium, low; PO/PM and admins only, others get medium), module (name), description, environment, app_version, build, device, operating_system, preconditions, steps_to_reproduce, actual_result, expected_result, impact, suggested_solution, parent (code or id of the parent issue: the epic of a regular issue, or the issue of a subtask; the level comes from the type), story_points (a number from 0 to 1000), start_date and due_date (start and due date, YYYY-MM-DD; the start doesn't come after the due date), custom_fields (an object keyed by the field key), labels (up to 10 names; one that doesn't exist is created) and external_id (the id at the source, up to 200 characters).

Templates per type: description, preconditions, steps_to_reproduce, actual_result, expected_result, impact and suggested_solution when omitted come filled with the type's template (the template in GET /projects). Send "" to leave one of those fields empty.

Use external_id in CI: with the name of the failed test, for example, running the pipeline again doesn't duplicate the issue.