Dailybot Plan API
Plan and track work through the Dailybot Plan API (Beta): projects, boards, tasks and goals over one REST API, with the concepts you need before your first call.
Beta
Plan is in beta. Everything under /plan in the web app, the CLI and agent skill commands for projects, goals, boards and tasks, and the /v1/plan/ public API may change before general availability. Want to try it with your team? Write to [email protected].
Dailybot Plan is where a team plans and tracks its work: projects, boards, tasks and goals. The web app, the Dailybot CLI and the agent skill all use the same public API under https://api.dailybot.com/v1/plan/. There is no private API behind them, so anything one of them can do, your integration can do too.
This page explains the model once. Every other Plan page links back here.
Who can do what
Every authenticated non-guest member can use the whole Plan API: create and manage goals, projects, boards, states and memberships. A personal API key acts as its person and can do everything that person can do, so a member’s key needs no scope grant and no organization-admin role. Guests are refused before entitlement (403 guest_not_allowed), with a key or a session.
Privacy is invite / membership, not org role. Org-wide projects and boards are a shared workspace. A members container is 404 (not visible) without a grant. Invite a person or a team to share; the last grant on a private container is 409 last_grant_cannot_be_removed. There are no per-project roles (lead/viewer) — membership is a grant, not a role ladder.
Oversight: organization admins and managers of all teams can see every project. A members board still needs an explicit grant.
Agent and organization keys have no person behind them: they see organization-visible boards only and are refused (403 insufficient_scope) on the endpoints that need a person. Full detail: Authentication and scopes for Plan.
Start here
- Concepts: projects, goals, boards, columns, owners and executors, labels, views and the inbox, one paragraph each.
- Agents on Plan: let an agent read a card and write back as a person, with the agent shown on the card.
- Dailybot CLI for Plan and the agent skill: the command line and the public skill pack.
- Quickstart: your first calls in under five minutes (sign in, list boards, create, move and comment on a task).
- API reference: every endpoint, grouped into Projects, Goals, Boards, Tasks, Comments & files and Home & search.
- Authentication and scopes for Plan: the three credentials, what a personal API key can do, scopes, guests and privacy as membership.
- Conventions for Plan: pagination, filters, sorting,
include, rate limits,Idempotency-Key,If-Matchand304. - Errors for Plan: every code with its status, meaning and what to do next, including
402during the Beta. - Authentication and Errors: the rules shared by every Dailybot API.
Recipes
- Show a board and keep it fresh: snapshot, delta feed and server-paced polling.
- Render a home in one request: the home pulse and its bands.
- Create tasks from a list: bulk create with a dry run and idempotency.
- Move a task when a pull request merges: from any CI, addressed by key.
- Track progress against a goal: progress, projects and
is_partial. - React to changes with webhooks: the 25 events and verifying deliveries.
Check that Plan is enabled for your organization
Plan is in Beta and is enabled per organization. GET /v1/plan/entitlements/ is the one Plan endpoint that answers even when your organization is not enabled yet, so call it first:
curl -sS "https://api.dailybot.com/v1/plan/entitlements/" \
-H "Authorization: Bearer $DAILYBOT_TOKEN"
{
"enabled": false,
"reason": "rollout",
"boards": { "used": 0, "limit": 3 },
"projects": { "used": 0, "limit": 1 },
"labels": { "enabled": true }
}
enabled: false with reason: "rollout" means your organization is not in the Beta yet. Every other Plan endpoint answers 402 plan_upgrade_required until it is: that is expected. Write to [email protected] to join.
The model: organization, project, board, task
Organization
└── Project what a body of work is (health, status notes, milestones)
└── Board where the work is tracked; its columns are workflow states
└── Task one unit of work, addressed as ENG-142
A board belongs to a project and a task belongs to a board. Tasks can have sub-tasks (one level deep), relations to other tasks (blocks, relates_to, duplicates), an owner, participants, labels, comments and attachments.
Workflow states and their five categories
A board’s columns are its workflow states. You can name them anything, but every state has one of five fixed categories, and the category is what answers “is this finished?” on any board:
| Category | Meaning | Counts as |
|---|---|---|
backlog |
Not planned yet | open |
todo |
Planned, not started | open |
in_progress |
Being worked on | open |
done |
Finished | done |
canceled |
Will not be done | done |
The state filter accepts two shortcuts built on these categories: open (backlog, todo, in_progress) and done (done, canceled). “Blocked” is not a category: it is derived from relations, so filter with blocked=true.
Goals point at work; they do not contain it
A goal says what the work is for, with a period (period_start, period_end) and a declared status. Nothing lives inside a goal. A project can point at several goals and a goal can be served by several projects, so archiving a goal leaves every project where it was.
A task can point at its own goal. When it does not, it inherits its project’s goal, and filters and progress roll-ups apply that same rule.
Goal progress is scoped to you: it counts only the tasks you can see, and is_partial: true tells you when some of the goal’s work is hidden from you. Never present it as an organization-wide number.
Identifiers: uuid and KEY-n
Every object has a uuid. A task also has a human-readable key, KEY-n, such as ENG-142: ENG is the board’s key and 142 is a per-board counter. Both work wherever a task is addressed, for example GET /v1/plan/tasks/ENG-142/.
A board’s key can be renamed and old keys keep resolving, so a link written last year still opens the card. Keys are never reused, even after a task or board is archived. Numeric ids are never accepted.
An identifier that does not exist and an identifier from another organization return the same 404 body, so the API never reveals whether something exists outside your organization.
Ordering: move relative to neighbours
Cards in a column are ordered by an opaque rank. Never compute a rank. Place a card relative to its neighbours instead: POST /v1/plan/tasks/{task_id}/move/ takes a target state and at most one of after / before (a task in that column). Send neither to append at the end. Two people dragging the same card at the same time both produce a valid order.
Moving is the only way to change a task’s state.
Versions and concurrent edits
Every task carries an integer version that increments on each write. To make sure you do not overwrite somebody else’s edit, send the version you loaded in the If-Match header (or as the body field version) when you update, move or move a task to another board. If the task changed meanwhile, the API answers 409 version_conflict with the current version in extra.current_version, so you can re-read and decide.
Without If-Match, the last write wins.
Archive is the delete
No public endpoint hard-deletes a task, a board or a project. Archiving is the delete, and it is reversible:
- Archiving a project cascades to its boards and their tasks; archiving a board cascades to its tasks; archiving a task archives its sub-tasks.
- Restore walks back up, never down: restoring a project does not restore the boards it archived, because the API cannot tell them apart from boards archived on purpose. Restore each one you want back.
- Tasks, boards, projects, goals and workflow states each have a
…/restore/endpoint. - The
DELETEendpoints for tasks and milestones are aliases that archive. - Archived rows stay readable: lists hide them unless you pass
include_archived=true, and a task stays readable by key or uuid. - Board keys stay reserved through archive and restore.
The archive endpoints, milestone completion and bulk calls accept ?dry_run=true, which returns the consequence (including a sentence to show a person) without writing anything.
Mentions
To mention someone in a comment or a project update, write <@DB@{uuid}>, using the person’s uuid from GET /v1/plan/boards/{board_id}/mentionables/:
Looks good. <@DB@00000000-0000-4000-8000-00000000000c> can you review the rollout plan?
Responses render mentions as display text in body and list the people in mentions[]: read them from there, never by parsing body. A uuid that names nobody in your organization is removed from the text. Comments support one level of threading through parent_comment.
Ignore values you do not recognise
Event types, relation types, state categories and the list of webhook events are additive: new values arrive in minor releases. A client that treats an unknown value as an error will break on a release that changed nothing for it. Skip what you do not know.
What Beta means here
Paths, fields and behaviour described on these pages can change before general availability; we announce changes in the API changelog. If something you rely on is missing or unclear, write to [email protected].