Skip to content
ver .md original

Convenções do Plan

Paginação, a gramática de filtros compartilhada, ordenação, include, erros, limites de requisições, idempotência, concorrência e leituras condicionais na API do Dailybot Plan (Beta).

Beta

Plan está em beta. Tudo o que está em /plan no aplicativo web, os comandos da CLI e da agent skill para projetos, metas, quadros e tarefas, e a API pública /v1/plan/ podem mudar antes da disponibilidade geral. Quer testar com sua equipe? Escreva para [email protected].

A API do Plan segue as convenções compartilhadas por todas as APIs do Dailybot e acrescenta algumas próprias: uma gramática de filtros compartilhada por listas, quadros e timeline; Idempotency-Key nas criações; If-Match para edições concorrentes; e ETag / 304 nas leituras mais pesadas. Esta página explica cada uma delas uma única vez.

Paginação

As listas usam páginas. Envie page (começa em 1) e page_size, ou os aliases limit e offset:

curl -sS "https://api.dailybot.com/v1/plan/tasks/?board=ENG&page=2&page_size=100" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"

Todas as listas respondem com o mesmo envelope:

{
  "count": 152,
  "next": "https://api.dailybot.com/v1/plan/tasks/?board=ENG&page=3&page_size=100",
  "previous": "https://api.dailybot.com/v1/plan/tasks/?board=ENG&page=1&page_size=100",
  "results": []
}
  • page_size é 50 por padrão e vai até 100. Valores maiores são ajustados ao máximo, nunca rejeitados: se você pedir 500, recebe 100.
  • O snapshot do quadro retorna no máximo 50 tarefas por coluna, porque traz as etiquetas de cada cartão.
  • Siga next até ele ser null. results é sempre um array.

O feed de mudanças do quadro não é uma página: ele retorna um cursor, não next. Veja a referência do feed de mudanças.

Filtros

A lista de tarefas, o snapshot do quadro e a timeline compartilham uma mesma gramática de filtros, então uma visualização salva funciona nos três. Repetir um parâmetro é OR; parâmetros diferentes são AND: ?board=ENG&board=OPS&state=open significa “tarefas abertas em ENG ou OPS”.

Parâmetro Aceita
board uuids ou chaves de quadro (ENG), repetível
project · goal · team uuids, repetível. goal corresponde à meta da própria tarefa ou à que ela herda do projeto
state uuids de estado, ou os atalhos open (backlog, todo, in_progress) e done (done, canceled)
category backlog, todo, in_progress, done, canceled
priority De 1 urgente a 5 nenhuma, repetível
owner Um uuid de usuário, me ou unowned, repetível: owner=me&owner=unowned são suas tarefas mais as que não têm responsável
participant · created_by uuids de usuário, repetível
label uuids de etiqueta, repetível (até 50)
due_before · due_after · start_before · start_after · completed_before · completed_after Datas ISO, inclusivas
has_due_date · has_start_date · has_dates · blocked true ou false
estimate_min · estimate_max Inteiros
search Texto buscado no título e na chave (até 256 caracteres)
updated_since Timestamp ISO
is_archived · include_archived true ou false: apenas linhas arquivadas, ou arquivadas e ativas juntas

Duas formas de escrever que vale lembrar:

  • Atrasado é due_before=<today>&state=open. Não existe state=overdue: ele responde 400 invalid_filter_value.
  • Trabalho bloqueado que exige ação é blocked=true&state=open. Uma tarefa concluída ainda pode ter um bloqueio ativo, então blocked=true sozinho também retorna trabalho concluído.

Na lista de tarefas, um parâmetro desconhecido é ignorado, mas o snapshot do quadro e GET /v1/plan/activity/ só aceitam os parâmetros que documentam e recusam qualquer outro com 400 invalid_filter_value. Um valor que a API não consegue interpretar é 400 invalid_filter_value em todos os casos. owner=me com uma API key da organização é 400 actor_required (veja Autenticação no Plan).

Ordenação e include

sort recebe um único campo, com o prefixo - para ordem decrescente (sort=-updated_at). Toda ordenação adiciona um critério de desempate estável, então uma linha nunca aparece em duas páginas. Um valor não suportado é 400 invalid_sort, nunca um fallback silencioso.

Algumas leituras incluem dados extras sob demanda com include, uma lista separada por vírgulas. Cada endpoint documenta seus tokens, por exemplo:

Endpoint Tokens de include
GET /v1/plan/tasks/{task_id}/ children, relations, participants, attachments, comment_count, activity, comments
GET /v1/plan/projects/ progress
GET /v1/plan/goals/ progress, projects
GET /v1/plan/pulse/ projects, attention, activity, goal_progress

Um token desconhecido é 400 invalid_filter_value; um include= vazio é ignorado.

Erros

Os erros trazem um detail legível para pessoas e, para tudo em que você possa querer basear uma decisão no código, um code estável e legível por máquina:

{
  "detail": "This task changed since you loaded it.",
  "code": "version_conflict",
  "extra": { "current_version": 9 }
}

Decida com base em code, nunca em detail. Erros de validação em um corpo listam mensagens por campo. Um objeto inexistente e um objeto de outra organização retornam o mesmo corpo 404. Cada código, com o que fazer em seguida, está em Erros do Plan.

Limites de requisições

Os limites se aplicam por ator (uma pessoa ou uma API key da organização), por minuto:

Chamadas Limite
Leituras 120 por minuto
Escritas 60 por minuto
Chamadas em massa 30 por minuto
Feed de mudanças do quadro 240 por minuto

Ao passar de um limite, a API responde 429 com um cabeçalho Retry-After: aguarde essa quantidade de segundos antes de tentar de novo. Para um quadro ao vivo, consulte o feed de mudanças no intervalo poll_after_seconds que ele sugere, em vez de usar um timer fixo.

Idempotência

Criações e muitas escritas aceitam um cabeçalho Idempotency-Key (a tabela Headers de cada endpoint informa): uma string única que você gera para uma intenção.

curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: import-row-42" \
  -d '{"board": "ENG", "title": "Write the migration guide"}'
  • Enviar de novo a mesma chave com o mesmo corpo retorna a primeira resposta, não executa nada novo e adiciona o cabeçalho Idempotency-Replayed: true. Tente de novo com segurança depois de um timeout.
  • Enviar a mesma chave com um corpo diferente é 409 idempotency_key_payload_mismatch: uma chave identifica uma única intenção.
  • Uma repetição enviada enquanto a primeira chamada ainda está em andamento recebe 409 idempotency_in_progress por até 120 segundos.
  • As chaves ficam guardadas por 24 horas.
  • Operações em massa exigem a chave: POST /v1/plan/tasks/bulk/ sem chave é 400 idempotency_key_required.

Edições concorrentes

Toda tarefa tem um version inteiro. Para não sobrescrever a alteração de outra pessoa, envie a versão que você carregou em If-Match (entre aspas) ou no campo do corpo version:

curl -sS -X PATCH "https://api.dailybot.com/v1/plan/tasks/ENG-142/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -H 'If-Match: "7"' \
  -d '{"due_date": "2026-10-22"}'
  • Se a tarefa mudou, a resposta é 409 version_conflict com extra.current_version: leia de novo, concilie e tente outra vez.
  • Enviar If-Match e version com valores diferentes é 400 version_precondition_ambiguous.
  • Sem nenhum dos dois, vale a última escrita.
  • Hoje, a atualização de tarefa, a movimentação e a movimentação para outro quadro verificam versões.

Visualizações salvas funcionam de outro jeito: PUT …/views/ substitui a sua lista inteira, então exige If-Match com o ETag da sua última leitura. Um valor desatualizado é 412 precondition_failed; se ele faltar, é 428 precondition_required.

Leituras condicionais

O snapshot do quadro, o detalhe da tarefa e o pulse da página inicial retornam um ETag. Envie-o de volta em If-None-Match; se nada mudou, a API responde 304 Not Modified com o corpo vazio, e você não precisa processar uma resposta que já tem:

curl -sS -i "https://api.dailybot.com/v1/plan/boards/$BOARD/board/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "If-None-Match: $ETAG"

Prévias com dry_run

Os endpoints de arquivamento, a conclusão de marcos e as chamadas em massa aceitam ?dry_run=true. A API calcula a consequência e a retorna sem gravar nada, incluindo consequence, uma frase feita para ser mostrada a uma pessoa antes de ela confirmar:

curl -sS -X POST "https://api.dailybot.com/v1/plan/boards/$BOARD/archive/?dry_run=true" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN"

Atribuição de agente

Quando um agente trabalha com a credencial de uma pessoa, a pessoa é a autora de cada escrita e o agente é mostrado como quem a executou em seu nome. Nomeie o agente em cada escrita:

Escrita Como enviar o nome
Corpo JSON O campo agent_name do corpo (canônico)
Multipart, ou sem corpo (DELETE, arquivar, restaurar) O header X-Dailybot-Agent-Name, com o valor codificado em percent-encoding (UTF-8)
curl -sS -X POST "https://api.dailybot.com/v1/plan/tasks/ENG-142/comments/" \
  -H "Authorization: Bearer $DAILYBOT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"body": "Guia de migração redigido.", "agent_name": "Agente de releases"}'
  • Se os dois vierem, o corpo vence. Caracteres de controle são removidos e um nome em branco significa sem agente.
  • O máximo é de 128 caracteres. Um nome maior ou impossível de decodificar é 400 invalid_agent_attribution; nunca é truncado.
  • Todo endpoint de /v1/plan/ que altera dados (POST, PUT, PATCH, DELETE) o aceita. Os GET o ignoram.
  • Uma key do tipo agente, que não está ligada a uma pessoa, recebe 400 invalid_agent_attribution se enviar um nome.
  • O selo nunca altera uma resposta de permissão.
  • O nome é resolvido no mesmo registro de agentes de /v1/agent-reports/ (nome, aliases, avatar).
  • Um nome só pode usar letras, números, espaços e . - _ ( ) ' # + / & , :. Qualquer outra coisa, e o nome de um agente desativado, é 400 invalid_agent_attribution.
  • Um comentário escrito com uma API key ou selado com um agente tem provenance: agent_authored.

Nas respostas, comentários, anexos e itens de atividade trazem executed_by_agent ({uuid, name, username, avatar}, ou null) ao lado do autor ou ator. Uma tarefa ganha executors, uma lista de {uuid, name, username, avatar, first_at, last_at}, do mais recente ao mais antigo. É separada do executor singular, que continua sendo quem está com a bola agora.

Pelo CLI do Dailybot (4.0.0 e posteriores): passe --agent-name (ou defina DAILYBOT_AGENT_NAME; a flag vence). Sem nenhum dos dois, uma pessoa está agindo diretamente e nada é selado. É um rótulo de atribuição, nunca uma credencial, então não altera nenhuma permissão. O CLI envia agent_name em escritas JSON e o header em uploads e escritas sem corpo, nunca em leituras, e recusa localmente nomes com mais de 128 caracteres.

dailybot --agent-name "Claude Code" plan task comment ENG-12 "Reproduzido e corrigido"

task comments mostra Jane Doe via "Claude Code", e task get acrescenta uma linha Agents com os executores, do mais recente ao mais antigo. task brief [--download DIR] [--force] [--json] lê um cartão inteiro para um agente, anexos incluídos.

Mudanças aditivas

Durante a Beta, novos campos, parâmetros, tipos de evento, tipos de relação e categorias de estado podem aparecer a qualquer momento. Ignore os valores que você não reconhecer e acompanhe o changelog da API.