Planning for integrators and assistants
What this page is — Every way software, rather than a person at the Planning screen, reaches the plan: the Orbit Public API, the planning.committed webhook, the MCP tools an AI agent uses, the client SDKs, and the questions the Orbit Assistant can answer about plans, capacity and hires.
What it is for — Feeding the committed sprint plan into a BI tool, a resourcing system or a status page; preparing scenarios and planned hires from a recruiting or portfolio tool; and letting people ask "which sprints are over capacity?" in plain language.
The problem it solves — A plan that lives only on one screen gets copied into spreadsheets by hand and is stale the day after. These interfaces read the same plan the screen shows, so other systems stay current without anyone re-typing it — while the one decision that changes real tasks, the commit, stays with a person in the app.
Base path: /api/v1/ext/task/planning · Credentials: an API key from Developers → API keys carrying the Planning scopes below · Assistant: needs View planning
Module: Planning · Entry points: the developers portal (developers.<your-domain> — Orbit Ops → Planning) · Developers → Webhooks · the Orbit Assistant · Ask AI in the Planning header
1. What is available, and to whom
| Interface | Direction | Who uses it | Reads | Writes |
|---|---|---|---|---|
| Public API | Your system → Orbit | Integrations with an API key | Tree, committed plans, burndown, scenarios, commits, planned hires, task planning fields | Draft scenarios, planned hires, task planning fields |
Webhook planning.committed | Orbit → your system | Integrations subscribed on Developers → Webhooks | — | — (a notification) |
| MCP tools | An AI agent → Orbit | Agents connected with an API key | Same as the API | Same as the API |
| Client SDKs | Your code → Orbit | TypeScript and Python developers | Same as the API | Same as the API |
| Orbit Assistant | A person → Orbit | Anyone with View planning | Summary, time boxes, one sprint, scenarios, commits, hires | Nothing |
What is deliberately not exposed. Committing a scenario rewrites many tasks at once — sprint, assignee, estimates — and notifies people. It is a human decision taken in the app with its preview, so no API, MCP tool, SDK method or assistant question can commit. The same goes for the board moves inside a scenario, drift and rebase, Compare, Suggest with AI and the AI goal check: an integration prepares the inputs (a scenario, a hire, task estimates) and reads the outcome, and subscribes to planning.committed to learn when a person committed.
2. Why you would use it
- Report on plans without exporting. A BI tool reads committed capacity, committed hours and the burndown every night, so the portfolio dashboard is never a week old.
- Keep hiring and planning in step. When a requisition opens in your recruiting system, create the planned hire in Orbit with its hours and start date; planners can put work on it the same day.
- React to a commit. The webhook tells a status page, a chat channel or a finance system the moment a sprint plan is locked in, with counters of what changed.
- Answer questions in seconds. The assistant answers "is the next sprint on track?" from the committed plan, for free, without anyone opening Planning.
3. Step by step — connect an integration
- Developers → API keys — create a key and tick task:planning:read (and task:planning:write if the integration creates scenarios or hires). Existing keys do not gain these scopes automatically; edit the key to add them. Bind the key to one project if the integration should only ever see that project.
- Send the key on every call —
X-Orbit-API-Key: <key>orAuthorization: Bearer <key>. - Call
GET /treeto learn the project's phases, sprints and milestones. A SPRINT or PHASEidis a time box id; a MILESTONEidis what a task contributes to. - Read a sprint:
GET /timeboxes/{id}/planfor the committed plan,GET /timeboxes/{id}/burndownfor the daily series. - On POSTs, send an
Idempotency-Keyheader, unique per logical operation, so a retry never creates a second scenario or hire. - Developers → Webhooks — add your endpoint and tick
planning.committedin the Orbit Ops – Planning group.
The organisation, and the project for a project-bound key, always come from the key. An org-wide key passes project_id as a query parameter on project-level calls.
4. Field reference
Scopes
| Scope | Allows |
|---|---|
task:planning:read | Read planning: committed time-box plans and capacity, burndown, scenarios, commits and planned hires |
task:planning:write | Create planning scenarios and planned hires (never writes tasks) |
The ten endpoints (prefix /api/v1/ext/task/planning)
| Method and path | Scope | What it returns or does |
|---|---|---|
GET /tree | read | phases with their child sprints and milestones, plus orphans; each node carries its committed plan summary (or null), open and done task counts and date warnings (sprint_outside_phase, sprint_overlap, phase_outside_project, milestone_outside_phase) |
GET /timeboxes/{id}/plan | read | The committed plan of a sprint or phase: goal, success criteria, per-person capacity rows with names, committed hours, points and tasks, hire capacity, last goal-check verdict. 404 no_plan when nothing was committed; 422 for a MILESTONE id |
GET /timeboxes/{id}/burndown | read | Daily snapshots oldest first, the ideal line, and a live today point. Query days (0–3650, 0 = all) |
GET /scenarios | read | Scenario summaries, newest first. Query status — any of draft, committed, archived; default draft,committed |
POST /scenarios | write | Seeds a draft scenario. Body: name (required, unique in the project — 409 name_taken otherwise), timebox_ids (required, at least one SPRINT or PHASE id; a phase pulls its sprints in), notes, include_backlog (default true). Nothing about any task changes |
GET /scenarios/{id} | read | One scenario summary: status, time boxes, drift flag and count, item count, who created and who committed |
GET /commits | read | Commit summaries, newest first. Query limit 1–200, default 20 |
GET /commits/{id} | read | One commit with every task field it wrote (diffs), the warnings that were accepted, and the capacity and goals it committed |
GET /virtual-resources | read | Planned hires. Query status — any of active, hired, cancelled; default active,hired. A project-bound key sees only hires linked to its project |
POST /virtual-resources | write | Creates a planned hire. Body: name (required), role_text, skills, hours_per_week (0–168, default 40), zone_id, available_from / available_to (YYYY-MM-DD, end not before start), notes, project_ids. Never assigns tasks |
Task and milestone planning fields
The task and milestone endpoints of the Orbit Ops API carry the planning vocabulary:
| Where | Field | Meaning |
|---|---|---|
| Task (create, update, read) | milestone | The task's time box — a SPRINT or PHASE id. A MILESTONE id sent here is stored as target_milestone_id instead |
| Task (create, update, read) | target_milestone_id | The MILESTONE the task contributes to; another type answers 422 target_must_be_milestone; null clears |
| Task (create, update, read) | story_points | Size in points (0–99999). When estimated_hours is omitted it is derived from the project's size scale |
| Task (read only) | estimate_source | points when the hours were derived from points, otherwise manual |
| Task (read only) | planned_resource_id | The planned hire the work was committed to while nobody is assigned; set only by a commit |
| Task list filters | timebox_id · target_milestone_id | Comma-separated ids, exact match |
| Milestone (read) | type · parent_id | PHASE, SPRINT or MILESTONE; the phase a sprint or milestone belongs to |
| Milestone (read) | goal · plan_status | The committed goal, and committed when a plan was committed for that box |
A change that breaks the project's date rules answers 422 with the rule's code, the same rule the Roadmap enforces.
Webhook planning.committed
Sent once after every successful commit made in the app. The payload:
| Field | Meaning |
|---|---|
commit_id | Read the full commit with GET /commits/{commit_id} |
scenario_id · scenario_name | The scenario that was committed |
project_id | The project |
committed_by | The user who pressed Commit |
summary | Counters: tasks_changed, moved, reassigned, re_estimated, hires_assigned, timeboxes, net_capacity_hours, committed_hours |
Delivery, signing and retries work exactly as for every other Orbit webhook configured under Developers → Webhooks.
MCP tools
An agent connected to the Orbit MCP server with a key carrying the Planning scopes sees ten tools, one per endpoint:
| Tool | Endpoint | Scope |
|---|---|---|
get_planning_tree | GET /tree | read |
get_planning_timebox_plan | GET /timeboxes/{id}/plan | read |
get_planning_timebox_burndown | GET /timeboxes/{id}/burndown | read |
list_planning_scenarios | GET /scenarios | read |
create_planning_scenario | POST /scenarios | write |
get_planning_scenario | GET /scenarios/{id} | read |
list_planning_commits | GET /commits | read |
get_planning_commit | GET /commits/{id} | read |
list_planning_virtual_resources | GET /virtual-resources | read |
create_planning_virtual_resource | POST /virtual-resources | write |
A tool whose scope the key lacks is simply not offered to the agent.
SDK methods
Both reference clients on the developers portal group Planning under the task namespace:
| Endpoint | TypeScript (client.task.…) | Python (client.task.…) |
|---|---|---|
GET /tree | planningTree() | planning_tree() |
GET /timeboxes/{id}/plan | timeboxPlan(timeboxId) | timebox_plan(timebox_id) |
GET /timeboxes/{id}/burndown | timeboxBurndown(timeboxId, { days }) | timebox_burndown(timebox_id, days=None) |
GET /scenarios | listScenarios({ status }) | list_scenarios(status=None) |
GET /scenarios/{id} | getScenario(id) | get_scenario(scenario_id) |
POST /scenarios | createScenario(body) | create_scenario(body) |
GET /commits | listCommits({ limit }) | list_commits(limit=None) |
GET /commits/{id} | getCommit(id) | get_commit(commit_id) |
GET /virtual-resources | listPlannedHires({ status }) | list_planned_hires(status=None) |
POST /virtual-resources | createPlannedHire(body) | create_planned_hire(body) |
Project-level methods also accept a project id for org-wide keys; the Python create methods accept an idempotency_key.
Orbit Assistant — questions and the tools behind them
The assistant (and the voice assistant, which shows checking planning, reading sprint capacity and similar while it works) answers from six read-only tools. All are free, need View planning, and only read projects you are a member of.
| Ask something like | Tool | What comes back |
|---|---|---|
| "How is planning looking?" · "Any overcommitted sprints?" | planning.summary | Active and overcommitted time boxes, commits in the last 7 days, draft and drifted scenarios, active hires, tasks waiting on a hire, and the sprint ending soonest with its load against capacity |
| "Which sprints are over capacity?" · "What sprints are running?" | planning.timeboxes | Active and upcoming sprints and phases with committed goal, net capacity, open load, ratio, state and days left |
| "Is Sprint 14 on track?" · "Who has spare capacity in Sprint 14?" | planning.timebox.get | One sprint or phase by name: goal and criteria, each person's and hire's capacity against load and spare hours, the last goal-check verdict and the last 7 burndown points. It never runs a new goal check |
| "What planning scenarios do we have?" | planning.scenarios | Name, status, drift and its count, item count, last update, who committed and when |
| "Who committed the last plan and what changed?" | planning.commits | Recent commits with their counters and warnings |
| "Which hires are we planning?" | planning.hires | The organisation's planned hires: role, skills, hours, window, status, who replaced them, linked projects, and open tasks still waiting on each |
The Ask AI button in the Planning header offers three of these as starters.
5. Worked example
A company runs its recruiting in an applicant-tracking system and its portfolio reporting in a BI tool.
- When the ATS opens the requisition Backend dev #2, a small job calls
POST /api/v1/ext/task/planning/virtual-resourceswithname: "Backend dev #2",role_text: "Senior Go engineer",hours_per_week: 40,available_from: "2026-10-01",project_idsset to the Checkout project, and anIdempotency-Keyof the requisition number. The planner sees the hire under Link existing hire within seconds and plans four tasks on it in the scenario Q4 — hire two backend devs. - On Friday the planner commits. Orbit sends
planning.committedwithscenario_name: "Q4 — hire two backend devs"andsummary.hires_assigned: 4. The integration posts a message to the delivery channel and callsGET /commits/{commit_id}to store the diffs. - Every night the BI tool calls
GET /tree, thenGET /timeboxes/{id}/planandGET /timeboxes/{id}/burndown?days=14for each active sprint, and charts committed hours against net capacity across all projects. - On Monday the delivery lead asks the assistant "Is Sprint 14 on track?". It calls
planning.timebox.getand answers that Sprint 14 is at 96% of net capacity, the goal check from Thursday said on track, and one engineer has 6 hours spare. - When the hire signs, the ATS cannot replace the hire — that stays a planner's action in the Capacity grid (Replace with real user…) — so the job posts a reminder to the planner instead.
6. The admin contract
- Keys need the scopes explicitly. Keys created before Planning existed never gain
task:planning:readortask:planning:writeon their own. - A project-bound key sees only its project's plan, and only the hires linked to that project; it can link a new hire to its own project only.
- Webhook subscriptions are per event: tick
planning.committedunder Orbit Ops – Planning on each endpoint that should receive it. - The assistant follows the user's permissions, not a key: without View planning it declines planning questions.
- Rate limits and idempotency follow the Orbit Public API defaults described on the developers portal.
7. Don't confuse this with…
- Scenarios and commit — where a person moves tasks, runs Suggest with AI and commits. None of that is available through the API.
- Delivery forecast — has its own endpoint and scope (
task:risk:read); the Planning scopes do not include it. - The Plan committed notification — a bell alert and email to the project's managers and leads. The webhook is the machine-readable equivalent for other systems.
8. Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
403 on every Planning call | The key lacks task:planning:read | Edit the key and add the scope |
404 no_plan from /timeboxes/{id}/plan | Nothing has been committed for that sprint yet | Read /tree — plan is null there too; wait for a commit |
422 from /timeboxes/{id}/plan | The id is a MILESTONE, not a sprint or phase | Use a SPRINT or PHASE id from /tree |
409 name_taken creating a scenario | A scenario with that name already exists in the project | Choose another name, or read the existing one |
| A created hire does not appear on the Capacity grid | The hire is linked to the project but not yet added to the scenario | The planner uses Link existing hire → Add to scenario |
No planning.committed deliveries | The endpoint is not subscribed to the event, or nobody has committed | Tick the event on Developers → Webhooks; check the commit history on the Live tab |
| The agent does not list any planning tools | The MCP key lacks the Planning scopes | Add them to the key and reconnect the agent |
| The assistant reports no capacity or goal for a busy sprint | The sprint was planned on the live board and never committed, so it has no committed capacity or goal | Commit a scenario that includes it |