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
nextaté ele sernull.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 existestate=overdue: ele responde400 invalid_filter_value. - Trabalho bloqueado que exige ação é
blocked=true&state=open. Uma tarefa concluída ainda pode ter um bloqueio ativo, entãoblocked=truesozinho 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_progresspor 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_conflictcomextra.current_version: leia de novo, concilie e tente outra vez. - Enviar
If-Matcheversioncom 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. OsGETo ignoram. - Uma key do tipo agente, que não está ligada a uma pessoa, recebe
400 invalid_agent_attributionse 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.