NoteBugsDocs

Referência da API

Cards

Criar, ler, editar, mover e apagar, mais as duas rotas de lote.

O card é a entidade de primeiro nível: tenantId é obrigatório na criação e imutável dali em diante. Antes de mandar columnId, confira qual conjunto de colunas vale para o card.

POST/api/cards
Papel: MembroEspaço de trabalho

Cria um card, do zero ou a partir de um modelo.

title e columnId deixam de ser obrigatórios quando vem templateId: a composição é “o que veio no pedido vence, o modelo preenche o que faltou”. O que sobrar vazio depois disso é recusado com 422.

Corpo da requisição

CampoTipoDescrição
tenantIdobrigatóriocuidObrigatório e IMUTÁVEL: o card nasce dentro de um espaço e nunca sai dele.
templateIdcuid | nullO modelo que preenche o que o corpo não trouxe. Precisa ser do mesmo espaço.
titlestring
descriptionstring
columnIdcuidPrecisa ser do conjunto em vigor para este card; ver columnScope.
projectIdcuid | nullnull deixa o card explicitamente sem projeto.
epicIdcuid | nullPrecisa ser um epic do MESMO projeto do card.
branchstring | nullCampo livre. String vazia é normalizada para null.
dueAtISO 8601 | nullInstante ISO 8601. Sem dueAtZone, o prazo não carrega o fuso em que foi declarado.
dueAtZoneIANA | nullO fuso em que o prazo foi DECLARADO (America/Sao_Paulo). É o que faz o mesmo dia valer para todo leitor.
tagIdscuid[]A lista FINAL de etiquetas, todas do mesmo espaço.

Requisição

curl -s -X POST http://localhost:3000/api/cards \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "cmsp4djx60002p801o7ybpkv7",
    "title": "Publicar a documentação",
    "description": "Site estático com a referência da API.",
    "columnId": "cmttg1vdl000tlf01uuqhz8ad",
    "projectId": "cmttg1vjy000zlf015g097nhi",
    "branch": "feature/api-documentation",
    "tagIds": ["cmttg1vnk0011lf01q0eswms5"]
  }'

Resposta201

{
  "id": "cmttg1vv00017lf01ol5bnlx2",
  "number": 198,
  "title": "Publicar a documentação",
  "description": "Site estático com a referência da API.",
  "columnId": "cmttg1vdl000tlf01uuqhz8ad",
  "projectId": "cmttg1vjy000zlf015g097nhi",
  "epicId": "cmttg1vs50015lf010l6k38uq",
  "branch": "feature/api-documentation",
  "dueAt": "2026-11-01T23:58:59.999Z",
  "dueAtZone": "America/Sao_Paulo",
  "favorite": false,
  "position": 0,
  "createdAt": "2026-09-09T01:52:58.764Z",
  "updatedAt": "2026-09-09T01:52:58.764Z",
  "tags": [{ "id": "cmttg1vnk0011lf01q0eswms5", "name": "api", "color": "mint" }],
  "attachments": [],
  "commentCount": 0
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não alcança o espaço de trabalho do recurso. É 403 e não 404 de propósito: assim a resposta não revela quais espaços existem.
404O recurso não existe, ou já foi apagado.
422O epic informado não é do mesmo projeto do card. A regra vale nos dois sentidos: mudar o projeto do card também é conferido.
422O corpo não passou pelo schema. O campo details traz fieldErrors e formErrors do zod, campo a campo.

O card nasce na primeira coluna do conjunto e no topo, com número sequencial que nunca é reaproveitado, e a criação já grava a gênese do histórico. Entrando num epic com alvo de data, o prazo pode ser herdado dele.

GET/api/cards/[id]
Papel: LeitorEspaço de trabalho

Um card, com etiquetas, anexos e a contagem de comentários.

Parâmetros de rota

CampoTipoDescrição
idobrigatóriocuid

Requisição

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

Resposta200

{
  "id": "cmttg1vv00017lf01ol5bnlx2",
  "number": 198,
  "title": "Publicar a documentação",
  "description": "Site estático com a referência da API.",
  "columnId": "cmttg1vdl000tlf01uuqhz8ad",
  "projectId": "cmttg1vjy000zlf015g097nhi",
  "epicId": "cmttg1vs50015lf010l6k38uq",
  "branch": "feature/api-documentation",
  "dueAt": "2026-11-01T23:58:59.999Z",
  "dueAtZone": "America/Sao_Paulo",
  "favorite": false,
  "position": 0,
  "createdAt": "2026-09-09T01:52:58.764Z",
  "updatedAt": "2026-09-09T01:52:58.764Z",
  "tags": [{ "id": "cmttg1vnk0011lf01q0eswms5", "name": "api", "color": "mint" }],
  "attachments": [],
  "commentCount": 0
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não alcança o espaço de trabalho do recurso. É 403 e não 404 de propósito: assim a resposta não revela quais espaços existem.
404O recurso não existe, ou já foi apagado.

favorite é a resposta para QUEM PEDIU: a marca é pessoal e mora numa linha própria, então dois leitores recebem valores diferentes para o mesmo card.

PATCH/api/cards/[id]
Papel: MembroEspaço de trabalho

Edita um card. Campo ausente não é tocado.

Aceita { dueAt } ou { favorite } sozinhos: é o que a estrela e o seletor de prazo da interface usam, sem rota própria para cada um.

Parâmetros de rota

CampoTipoDescrição
idobrigatóriocuid

Corpo da requisição

CampoTipoDescrição
titlestring
descriptionstring
columnIdcuidTrocar de coluna aqui grava histórico, igual ao arraste.
projectIdcuid | null
epicIdcuid | nullnull tira o card do epic; o card continua no projeto.
branchstring | null
dueAtISO 8601 | null
dueAtZoneIANA | nullAusente PRESERVA o fuso já gravado: não cai no fuso de quem está chamando.
favoritebooleanMarca pessoal. Nenhuma regra de epic, prazo ou histórico é acionada por este campo.
tagIdscuid[]A lista FINAL: o que não vier aqui é removido do card.

Requisição

# a estrela da interface manda só isto
curl -s -X PATCH http://localhost:3000/api/cards/cmttg1vv00017lf01ol5bnlx2 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "favorite": true }'

Resposta200

{
  "id": "cmttg1vv00017lf01ol5bnlx2",
  "number": 198,
  "title": "Publicar a documentação",
  "description": "Site estático com a referência da API.",
  "columnId": "cmttg1vdl000tlf01uuqhz8ad",
  "projectId": "cmttg1vjy000zlf015g097nhi",
  "epicId": "cmttg1vs50015lf010l6k38uq",
  "branch": "feature/api-documentation",
  "dueAt": "2026-11-01T23:58:59.999Z",
  "dueAtZone": "America/Sao_Paulo",
  "favorite": true,
  "position": 0,
  "createdAt": "2026-09-09T01:52:58.764Z",
  "updatedAt": "2026-09-09T01:52:58.764Z",
  "tags": [{ "id": "cmttg1vnk0011lf01q0eswms5", "name": "api", "color": "mint" }],
  "attachments": [],
  "commentCount": 0
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não alcança o espaço de trabalho do recurso. É 403 e não 404 de propósito: assim a resposta não revela quais espaços existem.
404O recurso não existe, ou já foi apagado.
422O corpo veio vazio. Campo ausente significa não mexe, então um PATCH sem nenhum campo não teria efeito nenhum.
422O epic informado não é do mesmo projeto do card. A regra vale nos dois sentidos: mudar o projeto do card também é conferido.

Limpar um campo exige valor explícito (null). Ausente significa “não mexe”, e é o que permite mandar um campo só.

DELETE/api/cards/[id]
Papel: MembroEspaço de trabalho

Apaga um card, com comentários, vínculos, histórico e os arquivos do volume.

Parâmetros de rota

CampoTipoDescrição
idobrigatóriocuid

Requisição

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

Resposta200

{ "deleted": true }

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não alcança o espaço de trabalho do recurso. É 403 e não 404 de propósito: assim a resposta não revela quais espaços existem.
404O recurso não existe, ou já foi apagado.
POST/api/cards/[id]/move
Papel: MembroEspaço de trabalho

Move o card para uma coluna e uma posição: é por aqui que passa o arraste.

A posição chega como afterCardId, e nunca como um índice: com um filtro ligado, o índice visível não corresponde ao índice real da coluna.

Parâmetros de rota

CampoTipoDescrição
idobrigatóriocuid

Corpo da requisição

CampoTipoDescrição
columnIdobrigatóriocuidA coluna de destino, do conjunto em vigor para este card.
afterCardIdobrigatóriocuid | nullO card depois do qual este fica. null solta no topo da coluna.

Requisição

# afterCardId null solta o card no TOPO da coluna
curl -s -X POST http://localhost:3000/api/cards/cmttg1vv00017lf01ol5bnlx2/move \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "columnId": "cmttg1vdl000ulf01nhqhd23w",
    "afterCardId": null
  }'

Resposta200

{
  "id": "cmttg1vv00017lf01ol5bnlx2",
  "number": 198,
  "title": "Publicar a documentação",
  "description": "Site estático com a referência da API.",
  "columnId": "cmttg1vdl000ulf01nhqhd23w",
  "projectId": "cmttg1vjy000zlf015g097nhi",
  "epicId": "cmttg1vs50015lf010l6k38uq",
  "branch": "feature/api-documentation",
  "dueAt": "2026-11-01T23:58:59.999Z",
  "dueAtZone": "America/Sao_Paulo",
  "favorite": false,
  "position": 0,
  "createdAt": "2026-09-09T01:52:58.764Z",
  "updatedAt": "2026-09-09T01:52:58.764Z",
  "tags": [{ "id": "cmttg1vnk0011lf01q0eswms5", "name": "api", "color": "mint" }],
  "attachments": [],
  "commentCount": 0
}

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não alcança o espaço de trabalho do recurso. É 403 e não 404 de propósito: assim a resposta não revela quais espaços existem.
404O recurso não existe, ou já foi apagado.
422A coluna não pertence ao conjunto em vigor para este card. Qual conjunto vale é decisão do columnScope.

Trocar de coluna grava uma linha de histórico; reordenar dentro da mesma coluna não gera registro.

PATCH/api/cards/bulk
Papel: MembroEspaço de trabalho

Edita os detalhes de vários cards de uma vez.

As etiquetas viajam como ADICIONA/REMOVE, e não como a lista final que o formulário de um card envia: substituir a lista apagaria as etiquetas que cada card já tinha.

Corpo da requisição

CampoTipoDescrição
cardIdsobrigatóriocuid[]De 1 a 200 cards. Todos os espaços envolvidos são conferidos.
branchstring | null
dueAtISO 8601 | nullnull limpa o prazo dos cards do lote.
dueAtZoneIANA | null
addTagIdscuid[]Etiquetas a acrescentar. Um id não pode estar aqui e em removeTagIds.
removeTagIdscuid[]Etiquetas a tirar.

Requisição

curl -s -X PATCH http://localhost:3000/api/cards/bulk \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardIds": ["cmttg1vv00017lf01ol5bnlx2", "cmttg1vyj001blf01888i4wn8"],
    "branch": "feature/api-documentation",
    "addTagIds": ["cmttg1vnk0011lf01q0eswms5"]
  }'

Resposta200

{ "updated": 2 }

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não alcança o espaço de trabalho do recurso. É 403 e não 404 de propósito: assim a resposta não revela quais espaços existem.
404O recurso não existe, ou já foi apagado.
422O lote não escolheu nenhum campo para alterar, ou pediu para adicionar e remover a mesma etiqueta.

O lote recusa inteiro: se um card quebra uma regra, nenhum é alterado. Título e coluna ficam de fora: são decisões card a card.

PATCH/api/cards/epic
Papel: MembroEspaço de trabalho

Move cards para dentro, para fora e entre epics.

As três são a mesma operação: gravar epicId (ou null) num conjunto de cards.

Corpo da requisição

CampoTipoDescrição
cardIdsobrigatóriocuid[]
epicIdobrigatóriocuid | nullnull tira os cards do epic; eles continuam no projeto.
alignDueAtbooleanOpt-in EXPLÍCITO para sobrescrever a data de quem vence depois do alvo do epic. Sem ele, o lote recusa em vez de apagar uma data escolhida.Ausente: false

Requisição

curl -s -X PATCH http://localhost:3000/api/cards/epic \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "cardIds": ["cmttg1vyj001blf01888i4wn8"],
    "epicId": "cmttg1vs50015lf010l6k38uq",
    "alignDueAt": true
  }'

Resposta200

{ "updated": 1 }

Respostas de erro

CódigoQuando acontece
401Sem credencial, ou com uma que não vale mais. Mande o cookie de sessão ou o cabeçalho Authorization: Bearer.
403A conta não alcança o espaço de trabalho do recurso. É 403 e não 404 de propósito: assim a resposta não revela quais espaços existem.
404O recurso não existe, ou já foi apagado.
422O epic está travado e não recebe cards novos. Destrave antes, ou escolha outro.
422Algum card do lote vence depois do alvo do epic. Mande alignDueAt: true para sobrescrever as datas: o servidor nunca apaga uma data escolhida sem pedido.