Browse the docs

API reference

Cycles

Timeboxed sprints of one to four weeks per product. Status is derived from the dates: planned before the start, active until completed. Two open cycles of a product never overlap.

List cycles

GET/v1/projects/{slug}/cycles

Every cycle of a product, oldest first, with done/started/open counts. currentId names the active one, or null. A completed cycle reports what it held when it closed.

Requires work.read

Path parameters

  • slugstringrequired

    The product's slug.

Request
curl "https://atrix.dev/api/v1/projects/SLUG/cycles" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "currentId": "cmc1y2c3l40001ab12cd34ef56",
  "cycles": [
    {
      "id": "cmc1y2c3l40001ab12cd34ef56",
      "number": 4,
      "name": "Cycle 4",
      "goal": "Ship retries and the billing page",
      "startsOn": "2026-10-26",
      "endsOn": "2026-11-08",
      "status": "active",
      "overdue": false,
      "daysLeft": 12,
      "completedAt": null,
      "progress": {
        "total": 9,
        "done": 3,
        "started": 2,
        "open": 6,
        "cancelled": 1
      }
    }
  ]
}

Create a cycle

POST/v1/projects/{slug}/cycles

Starts a cycle. Without startsOn it begins the day after the last open cycle ends, or today. Numbers are sequential per product. An overlap with an open cycle comes back as { error } naming it.

Requires work.write

Path parameters

  • slugstringrequired

    The product's slug.

Body

  • weeksinteger

    Length, 1 to 4. Defaults to 2.

  • startsOnISO date

    First day (YYYY-MM-DD).

  • namestring | null

    Optional; shown as "Cycle N" without one.

  • goalstring | null

    What the cycle is for.

Request
curl -X POST "https://atrix.dev/api/v1/projects/SLUG/cycles" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "weeks": 1, "startsOn": "2026-11-02" }'
Response
{
  "ok": true,
  "id": "cmc1y2c3l40001ab12cd34ef56",
  "number": 4,
  "startsOn": "2026-10-26",
  "endsOn": "2026-11-08"
}

Get a cycle

GET/v1/projects/{slug}/cycles/{id}

One cycle with its issues, progress, added (issues that joined after the first day) and burndown: one point per day to today, the live scope and what was still open at the end of that day, read from the status history.

Requires work.read

Path parameters

  • slugstringrequired

    The product's slug.

  • idstringrequired

    The cycle id.

Request
curl "https://atrix.dev/api/v1/projects/SLUG/cycles/ID" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "id": "cmc1y2c3l40001ab12cd34ef56",
  "number": 4,
  "name": "Cycle 4",
  "goal": "Ship retries and the billing page",
  "startsOn": "2026-10-26",
  "endsOn": "2026-11-08",
  "status": "active",
  "overdue": false,
  "daysLeft": 12,
  "completedAt": null,
  "progress": {
    "total": 9,
    "done": 3,
    "started": 2,
    "open": 6,
    "cancelled": 1
  },
  "added": 2,
  "burndown": [
    {
      "day": "2026-10-26",
      "scope": 8,
      "remaining": 8
    },
    {
      "day": "2026-10-27",
      "scope": 9,
      "remaining": 6
    }
  ],
  "summary": null,
  "issues": [
    {
      "id": "cm9x2k7f40001ab12cd34ef56",
      "title": "Retry failed Stripe webhooks",
      "status": "IN_PROGRESS",
      "type": "TASK",
      "priority": "HIGH",
      "dueOn": "2026-10-30",
      "assignee": {
        "id": "cm8q1z0a10003xy98wv76ut54",
        "name": "Sara Khan"
      }
    }
  ]
}

Update a cycle

PATCH/v1/projects/{slug}/cycles/{id}

Renames it, rewrites its goal or moves its dates (at most 4 weeks, never overlapping another open cycle). A completed cycle keeps its dates.

Requires work.write

Path parameters

  • slugstringrequired

    The product's slug.

  • idstringrequired

    The cycle id.

Body

  • namestring | null

    New name, or null for "Cycle N".

  • goalstring | null

    New goal, or null to clear it.

  • startsOnISO date

    New first day.

  • endsOnISO date

    New last day, inclusive.

Request
curl -X PATCH "https://atrix.dev/api/v1/projects/SLUG/cycles/ID" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "name": "…", "goal": "…" }'
Response
{
  "ok": true
}

Delete a cycle

DELETE/v1/projects/{slug}/cycles/{id}

Removes the cycle. Its issues are kept and simply have no cycle.

Requires work.write

Path parameters

  • slugstringrequired

    The product's slug.

  • idstringrequired

    The cycle id.

Request
curl -X DELETE "https://atrix.dev/api/v1/projects/SLUG/cycles/ID" \
  -H "Authorization: Bearer $ATRIX_TOKEN"
Response
{
  "ok": true
}

Complete a cycle

POST/v1/projects/{slug}/cycles/{id}/complete

Closes an active cycle and moves its unfinished work. The summary is counted before anything moves. Closing early pulls the end date in to today.

Requires work.write

Path parameters

  • slugstringrequired

    The product's slug.

  • idstringrequired

    The cycle id.

Body

  • rolloverenumrequired

    next: into the next open cycle, made (same length) if there is none. backlog: out of any cycle and back to BACKLOG status.

    nextbacklog

Request
curl -X POST "https://atrix.dev/api/v1/projects/SLUG/cycles/ID/complete" \
  -H "Authorization: Bearer $ATRIX_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "rollover": "next" }'
Response
{
  "ok": true,
  "summary": {
    "done": 6,
    "open": 2,
    "cancelled": 1,
    "total": 8,
    "added": 2,
    "rollover": "next",
    "rolledTo": {
      "id": "cmc1y2c3l40002ab12cd34ef56",
      "number": 5
    }
  }
}