NoteBugsDocs

API reference

Epics

The delivery grouping inside a project.

It is the only creation that does not ask for tenantId: an epic inherits the project's workspace. With the feature turned off in Settings, all of these routes answer 403.

GET/api/epics
Role: ViewerWorkspace

The epics of every workspace the account reaches.

Request

curl -s http://localhost:3000/api/epics \
  -H "Authorization: Bearer $TOKEN"

Response200

[
  {
    "id": "cmttg1vs50015lf010l6k38uq",
    "projectId": "cmttg1vjy000zlf015g097nhi",
    "name": "Onboarding",
    "description": null,
    "color": "amber",
    "status": "ACTIVE",
    "locked": false,
    "dueAt": "2026-10-31T23:59:00.000Z",
    "dueAtZone": "America/Sao_Paulo",
    "position": 0
  }
]

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.

An epic has no tenantId (it inherits the project's), so the filter goes through the project.

POST/api/epics
Role: MemberWorkspace

Creates an epic inside a project.

Request body

FieldTypeDescription
projectIdrequiredcuidRequired: a loose epic does not exist. The workspace comes from here.
namerequiredstring
descriptionstring | null
coloracento ou #rrggbb
dueAtISO 8601 | nullThe epic's target. Cards entering it may inherit this date.
dueAtZoneIANA | null

Request

curl -s -X POST http://localhost:3000/api/epics \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "cmttg1vjy000zlf015g097nhi",
    "name": "Onboarding",
    "color": "amber",
    "dueAt": "2026-10-31T23:59:00.000Z",
    "dueAtZone": "America/Sao_Paulo"
  }'

Response201

{
  "id": "cmttg1vs50015lf010l6k38uq",
  "projectId": "cmttg1vjy000zlf015g097nhi",
  "name": "Onboarding",
  "description": null,
  "color": "amber",
  "status": "ACTIVE",
  "locked": false,
  "dueAt": "2026-10-31T23:59:00.000Z",
  "dueAtZone": "America/Sao_Paulo",
  "position": 0
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403Epics are turned off in this installation's Settings.
403The account does not reach the resource's workspace. It is 403 and not 404 on purpose: the answer reveals no workspace.
404The resource does not exist, or has already been deleted.
422The body did not pass the schema. The details field carries zod's fieldErrors and formErrors, field by field.

This is the only creation route that does not ask for tenantId.

PATCH/api/epics/[id]
Role: MemberWorkspace

Edits the epic: name, colour, due date, lock and conclusion.

Path parameters

FieldTypeDescription
idrequiredcuid

Request body

FieldTypeDescription
namestring
descriptionstring | null
coloracento ou #rrggbb
statusenumDONE concludes the epic, and requires deciding what happens to the pending cards.ACTIVE · DONE
lockedbooleanLocks the epic: it stops taking new cards. Reversible and with no side effect.
dueAtISO 8601 | null
dueAtZoneIANA | null
pendingCardsenumDONE concludes the cards where they are; MOVE sends them to another epic.DONE · MOVE
pendingEpicIdcuidThe destination epic, and only when pendingCards is MOVE.
alignDueAtbooleanOverwrites the date of whoever is due after the target, while moving the pending cards.

Request

# locks the epic: it stops taking new cards
curl -s -X PATCH http://localhost:3000/api/epics/cmttg1vs50015lf010l6k38uq \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "locked": true }'

# concludes, deciding what happens to the cards still pending
curl -s -X PATCH http://localhost:3000/api/epics/cmttg1vs50015lf010l6k38uq \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "status": "DONE", "pendingCards": "DONE" }'

Response200

{
  "id": "cmttg1vs50015lf010l6k38uq",
  "projectId": "cmttg1vjy000zlf015g097nhi",
  "name": "Onboarding",
  "description": null,
  "color": "amber",
  "status": "ACTIVE",
  "locked": true,
  "dueAt": "2026-10-31T23:59:00.000Z",
  "dueAtZone": "America/Sao_Paulo",
  "position": 0
}

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403Epics are turned off in this installation's Settings.
404The resource does not exist, or has already been deleted.
422Concluding the epic requires deciding what happens to the cards that have not reached the done column: pendingCards with DONE or MOVE (and, in that case, pendingEpicId).
422The body came empty. An absent field means do not touch, so a PATCH with no field would have no effect at all.

There is no “leave it as it is” for pending cards.

DELETE/api/epics/[id]
Role: MemberWorkspace

Deletes the epic. Cards are released and stay in the project.

Path parameters

FieldTypeDescription
idrequiredcuid

Request

curl -s -X DELETE http://localhost:3000/api/epics/cmttg1vs50015lf010l6k38uq \
  -H "Authorization: Bearer $TOKEN"

Response200

{ "deleted": true, "cardsReleased": 3 }

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403Epics are turned off in this installation's Settings.
404The resource does not exist, or has already been deleted.
PATCH/api/epics/order
Role: MemberWorkspace

Reorders the epics of ONE project.

It takes a subset, like columns and workspaces.

Request body

FieldTypeDescription
projectIdrequiredcuid
epicIdsrequiredcuid[]

Request

curl -s -X PATCH http://localhost:3000/api/epics/order \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "projectId": "cmttg1vjy000zlf015g097nhi",
    "epicIds": ["cmttg1vs50015lf010l6k38uq"]
  }'

Response200

{ "updated": 0 }

Error responses

CodeWhen it happens
401No credential, or one that no longer holds. Send the session cookie or the Authorization: Bearer header.
403Epics are turned off in this installation's Settings.
404The resource does not exist, or has already been deleted.
422The given ids do not all belong to the same set. The route takes a subset, but it has to come from one place.