REST API

Releases and tests

Releases, release notes, test cases and test cycles.

  • GET /releases (tracker:read): releases with status, kind (version or ota), stage (current is the one that's live, one per track: the project's version and OTA each have their own; previous, approved, testing, development, planned, cancelled), stage_label (the name on screen), is_next (the next to go live), dates, open issues and the last Release Gate decision. Query: project and status (comma-separated list).
  • GET /releases/{id} (tracker:read): the release with kind, stage, stage_label, is_next, the screen's summary (summary: headline, context and next_step), the metrics and the gate suggestion (gate.applies; on an OTA without a BLOCKED recorded, gate.suggestion.decision is not_applicable and instead of the metrics comes gate.validation, the issue count: ready_for_qa, testing, approved, failed), the last decision, the issues, the test cycles and the release notes.
  • POST /releases (tracker:write): creates a release, {"project": "MOB", "version": "2.7.0", "build": "...", "environment": "...", "planned_date": "YYYY-MM-DD", "notes": "...", "kind": "version"}; kind is version (the default) or ota. A release that already went live (an OTA already sent, a backend deploy, a version published outside tracker) can be born in production, without the gate: "status": "production" and released_date (default: today). PO/PM or admin. The version is unique in the project: repeating the request returns the release that already exists (200, already_existed: true), without changing anything in it. For CI to record a delivery: POST /releases, then POST /issues/bulk with "action": "release" and the issues, and POST /releases/{id}/status.
  • POST /releases/{id}/status (tracker:write): {"status": "in_development"}. The path is planned → in_development → staging (testing), and from approved to production; cancelled leaves the path. An OTA (kind: "ota") goes to production directly, from planned, in_development, staging or approved, without the gate decision, unless the last decision is BLOCKED; validation follows afterwards through the linked issues (the summary.next_step of GET /releases/{id} says how many are in Ready for QA, testing, approved and failed). Other releases reach approved through the gate's APPROVED decision, recorded by a person on screen, and production requires that decision. Outside that path (approved directly, included) only an admin, with override_note.
  • POST /releases/{id}/move (tracker:write): {"to_project": "PLT"} moves the release to another project in the company (e.g. backend deploys born in the app go to the platform project). It takes history, gate decisions and notes along; the issues stay linked, even those from other projects. PO/PM or admin in both projects; the version can't exist in the target and a release with a test cycle doesn't move. MCP: move_release.
  • PUT /releases/{id}/notes (tracker:write): saves the release notes, the customer-facing text the screen copies and sends by e-mail: {"release_notes": "# App 2.7.0\n\n## What's new\n\n- You can now..."}. Simple markdown (# title, ## section, - item; no bold or links). Replaces the whole text; empty or null goes back to the draft generated from the resolved issues. PO/PM or admin. The response has release_notes and release_notes_saved. Doesn't send the e-mail.
  • GET /test-cases (tracker:read): active test cases. Query: project, q (part of the code or title) and include_archived.
  • POST /test-cases (tracker:write): creates a case, {"project": "MOB", "title": "...", "module": "...", "priority": "high", "steps": [{"action": "...", "expected": "..."}]}. QA or admin. The code (TC-MOB-0001) is generated.
  • GET /test-cycles (tracker:read): most recent cycles with their progress. Query: project and status.
  • GET /test-cycles/{id} (tracker:read): the cycle with each case and its result (pass, fail, blocked, in_progress, not_started), the comment, who tested and the issue opened from the fail.
  • POST /test-cycles (tracker:write): creates a cycle, {"project": "MOB", "name": "2.7.0 regression", "release": "2.7.0", "environment": "...", "cases": ["TC-MOB-0001"]}. Without cases, all the project's active cases go in. QA or admin.
  • POST /test-cycles/{id}/results (tracker:write): CI results, up to 200 per request, {"results": [{"test_case": "TC-MOB-0001", "status": "fail", "comment": "...", "open_issue": true}]}. status: pass, fail, blocked or in_progress; a comment is required for fail and blocked. With open_issue, the fail opens the issue already filled in with the case (or returns the one that already exists); if the issue doesn't open, the result stays saved and the item comes back with warning. Item by item, with recorded, failed and results. QA or admin.
  • POST /test-cycles/{id}/status (tracker:write): {"action": "start" | "finish" | "cancel" | "reopen"}. A closed cycle doesn't accept results until it's reopened.