Axuz Developers

Tarefas e boards pela API

Listar boards e colunas, buscar, criar, atualizar, mover e atribuir tarefas e comentar, com os campos, a paginação e os erros reais do axuz_workspace_api.

Tarefas e boards vivem no axuz_workspace_api, em https://api-workspace.axuz.net (staging; produção usa axuz.club). Todas as rotas ficam sob /teams/{teamId} e respondem JSON. Esta página descreve o contrato lido dos handlers, não de suposição.

Modelo

team contém boards. Um board pode estar ligado a um canal (na interface, “Channel”; no banco, timelines), caso em que cada canal tem no máximo um quadro. Cada board tem colunas ordenadas por position, e cada tarefa pertence a um board e a uma coluna.

Campos de uma tarefa (Task): id, team_id, board_id, column_id, parent_task_id, root_task_id, title, description, position (número fracionário), priority, status, start_at, due_at, is_all_day, created_by, created_at, updated_at, deleted_at, version.

  • priority: low, normal, high, urgent.
  • status: open, in_progress, done, blocked, cancelled.
  • start_at e due_at: YYYY-MM-DD quando is_all_day é true; senão RFC 3339 em UTC.
  • Mover para outra coluna não altera status: são campos independentes.

Board: id, team_id, timeline_id, name, description, created_by, created_at, updated_at. Coluna: id, team_id, board_id, name, position, created_at, updated_at.

Listar boards e colunas

GET/teams/{teamId}/boards

Devolve {"items":[Board]}, do mais novo para o mais antigo. Filtro opcional ?timeline_id=<uuid>; canal fora do seu alcance dá 404 channel not found. Sem filtro, só aparecem os boards de canais que o chamador alcança.

GET/teams/{teamId}/boards/{id}/columns

Devolve {"items":[Column]}. Para achar o quadro de um canal, use:

GET/teams/{teamId}/timelines/{timelineId}/board

Resposta 200 {"board":Board,"columns":[Column]}. Canal sem quadro devolve 404 com {"error":"board_not_found"}: não é falha do serviço, é o sinal de “crie o quadro”. O POST na mesma rota (postTeamsByTeamIdTimelinesByTimelineIdBoard, corpo opcional {"name"}) é idempotente: 201 se criou, 200 com o quadro existente.

curl -sS "https://api-workspace.axuz.net/teams/$AXUZ_TEAM_ID/boards/$AXUZ_BOARD_ID/columns" \
  -H "Authorization: Bearer $AXUZ_TOKEN"

Criar board (POST /teams/{teamId}/boards, postTeamsByTeamIdBoards) aceita name, description e timeline_id. Sempre envie name: com nome vazio o serviço pede um nome a um modelo de IA e, sem ele, usa Quadro de <nome do canal> ou Quadro AAAA-MM-DD. Criar coluna (POST /teams/{teamId}/boards/{id}/columns) exige name e aceita position de 0 a 999999; renomear ou reposicionar é PATCH /teams/{teamId}/columns/{id} com name e/ou position (corpo vazio dá 400 nothing to update).

Listar e buscar tarefas

GET/teams/{teamId}/boards/{id}/tasks

Devolve {"items":[Task]} com todas as tarefas vivas do board, ordenadas por coluna e posição. Filtre status no cliente (o exemplo descarta done e cancelled).

GET/teams/{teamId}/tasks/search

Parâmetros: q (substring do título, sem diferenciar maiúsculas; vazio devolve as mais recentes) e limit (padrão 10, máximo 25). Cada hit tem só id, title, board_id, board_name e status. A busca olha o time inteiro, mas só mostra tarefas de canais que o chamador alcança. Para ler uma tarefa inteira, use GET /teams/{teamId}/tasks/{id} (getTeamsByTeamIdTasksById), que dá 404 task not found se ela não existir ou estiver fora do alcance.

Criar uma tarefa

POST/teams/{teamId}/tasks
curl -sS -X POST "https://api-workspace.axuz.net/teams/$AXUZ_TEAM_ID/tasks" \
  -H "Authorization: Bearer $AXUZ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"board_id":"'"$AXUZ_BOARD_ID"'","column_id":"'"$AXUZ_COLUMN_ID"'","title":"Ligar para o fornecedor","priority":"high","due_at":"2026-11-03"}'

board_id, column_id e title são obrigatórios. Opcionais: description, priority, status, parent_task_id (subtarefa), start_at, due_at, is_all_day, position. Resposta 201 com a Task. Erros reais: 400 invalid board_id, invalid column_id, title required, invalid priority, invalid status, invalid due_at; 404 board not found quando o board não existe ou está fora do alcance.

Este POST não é idempotente: repetir cria outra tarefa. Controle isso no seu lado (id da mensagem do chat).

Atualizar, mover e atribuir

PATCH/teams/{teamId}/tasks/{id}

Todos os campos são opcionais, mas pelo menos um é obrigatório (400 nothing to update): column_id, title, description, position, priority, status, due_at, start_at. Para limpar uma data envie clear_due_at: true ou clear_start_at: true. is_all_day só vale com set_all_day: true.

Mover uma tarefa de coluna é um PATCH com column_id:

curl -sS -X PATCH "https://api-workspace.axuz.net/teams/$AXUZ_TEAM_ID/tasks/$AXUZ_TASK_ID" \
  -H "Authorization: Bearer $AXUZ_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"column_id":"'"$AXUZ_COLUMN_ID"'"}'

Para escolher a posição dentro da coluna use POST /teams/{teamId}/tasks/{id}/reorder (postTeamsByTeamIdTasksByIdReorder) com before_task_id e/ou after_task_id; responde {ok, position, task}. Vizinho inexistente dá 404 neighbor task not found.

PATCH e reorder exigem ser o autor da tarefa ou admin do canal; senão 403 forbidden: not author nor channel admin. Isso importa para bots: como o principal de integração ainda não está implementado nesse serviço, não dá para afirmar como essa regra se aplicará ao bot.

Atribuir: POST /teams/{teamId}/tasks/{id}/assignees com {"user_id":"<uuid>"} (postTeamsByTeamIdTasksByIdAssignees). Responde 201 se atribuiu agora e 200 se já estava (idempotente). Só aceita quem é membro ativo do time (422 user is not a team member). Listar: GET …/assignees devolve {"items":[{task_id,user_id,assigned_by,assigned_at}]}; remover: DELETE …/assignees/{userId} dá 204, mesmo se já não existia.

Comentar

POST/teams/{teamId}/comments

Comentários são polimórficos. Para tarefa: {"target_type":"task","target_id":"<uuid da tarefa>","body":"texto","body_format":"markdown"} (body_format é opcional, padrão markdown). Resposta 201 com id, team_id, author_id, target_type, target_id, body, body_format, created_at. Corpo vazio dá 400 body required; tarefa inexistente ou fora do alcance dá 404.

Listar: GET /teams/{teamId}/comments?target_type=task&target_id=<uuid> (getTeamsByTeamIdComments), em ordem cronológica, {"items":[…]}. O token de integração só pode comentar e listar com target_type=task.

Erros reais

O corpo é sempre {"error":"<mensagem>"}.

StatusMensagemQuando
400invalid body, invalid <campo>, nothing to update, title requiredJSON ruim, id que não é UUID, enum inválido, PATCH vazio
401unauthorizedCredencial ausente ou inválida
403forbidden: not author nor channel adminPATCH ou reorder sem ser autor/admin
404board not found, task not found, column not found, channel not foundNão existe ou está fora do seu alcance (não distingue)
404board_not_foundGET /timelines/{id}/board de um canal sem quadro
422user is not a team memberAtribuir a quem não é do time
429rate_limitedMutações acima de 60 por minuto; veja Retry-After
5xxinternal errorFalha interna; repita só GET e PATCH

Exemplo executável

examples/bot-node/ é um bot genérico em Node puro (fetch nativo, sem dependências): lista as tarefas abertas, cria uma, move para outra coluna pelo nome e comenta. O cliente HTTP está isolado em axuz-client.mjs (Bearer, retry com backoff, erro tipado), a lógica em bot.mjs, um adaptador de chat fictício em chat-adapter.mjs e a configuração vem só de variáveis de ambiente (config.mjs).

export AXUZ_BOT_TOKEN="axz_bot_..."   # do seu cofre, nunca do repositório
export AXUZ_TEAM_ID="<uuid do time>"
export AXUZ_BOARD_ID="<uuid do board>"
node examples/bot-node/index.mjs
# digite: /tarefas   /nova Ligar para o cliente   /mover <idDaTarefa> Fazendo   /comentar <idDaTarefa> feito

O teste (tests/examples/bot-node.test.ts) roda o mesmo código contra um servidor HTTP mock local, sem rede e sem segredo.

O que ainda não existe

  • Aceitar axz_bot_ nas rotas acima e atribuir a ação ao bot (autor, regra de PATCH, chave do rate limit).
  • Paginação keyset em boards, colunas, tarefas e comentários.
  • Idempotency-Key em POST /tasks e POST /comments.
  • Delete para o bot: por desenho nunca existirá.

Atualizado em