Project Canvas API
Base path: /api/projects/{project_id}
All endpoints require authentication. See API Overview for auth details. The views these endpoints serve are described in the Project Timeline & Canvas guide.
Live updates arrive on /ws/events as project.schedule.updated, project.canvas.updated and
project.canvas.generation (each payload names its project_id), plus swarm.schedule.slip
for a swarm run whose forecast slips past a confirmed deadline.
Schedule
Section titled “Schedule”Get the schedule
Section titled “Get the schedule”GET /api/projects/{project_id}/scheduleReturns the schedule settings and every item: {settings, items}.
Update settings
Section titled “Update settings”PUT /api/projects/{project_id}/scheduleAny of timezone (IANA name), start_date (YYYY-MM-DD), workdays (a list of weekday
numbers, Monday = 0 to Sunday = 6, never empty) and default_task_days (number). Only the keys you
send change; null clears timezone, start_date or default_task_days.
Add, change or remove an item
Section titled “Add, change or remove an item”POST /api/projects/{project_id}/schedule/itemsPATCH /api/projects/{project_id}/schedule/items/{item_id}DELETE /api/projects/{project_id}/schedule/items/{item_id}{ "kind": "deadline", "title": "Qloo contest due", "end_at": "2026-10-30", "task_ids": ["P2.4", "P2.5"], "confirmed": true, "note": "From the contest rules"}| Field | Notes |
|---|---|
kind | deadline, milestone, operator_step, or task_dates (a date override for tasks) |
start_at, end_at | A date (YYYY-MM-DD) or an ISO instant. A deadline uses end_at |
task_ids | Linked tasks: a swarm task’s short id (P1.4) or a standard project’s task id |
confirmed | Items the canvas generator proposes arrive false; only confirmed items count |
status | planned, done, missed or unknown |
Timeline
Section titled “Timeline”GET /api/projects/{project_id}/timeline?run_id=&tz=&group=The plan on a calendar. Rows come with start, end, basis (actual, running,
scheduled or derived), status and slip (the deadline a row ends after, and by how many
days). A running row’s start is real and its end is a forecast.
Deadlines and milestones come back separately.
| Parameter | Description |
|---|---|
run_id | Swarm projects: which run (default: the newest) |
tz | The viewer’s zone, used only when the schedule has none |
group | auto (default), generated, milestone, phase or owner |
Canvas
Section titled “Canvas”Read the canvas
Section titled “Read the canvas”GET /api/projects/{project_id}/canvas{ "canvas": {"canvas_id": "cnv_…", "project_kind": "swarm", "current_version_id": "cnvv_…"}, "version": {"version_id": "cnvv_…", "status": "ready", "tokens": 478146, "model": "…"}, "document": {"schema": "snippbot.canvas/1", "timeline": {}, "map": {}, "pairs": [], "layout": {}}, "overlay": [{"target": "/pairs/home/changes/0/text", "op": "set", "value": "…", "status": "ok"}], "staleness": {"stale": false, "affected_sections": []}, "generation": {"generation_id": "cgen_…", "state": "done"}, "mockups": {"mk_…": {"width": 390, "height": 844, "thumb_asset": "…"}}, "task_labels": {}}overlay holds your edits, each with a status: ok, conflict (the generator changed what
the edit was made over; generated holds the new value) or orphaned (its target is gone).
task_labels maps a standard project’s task ids to the short labels the canvas shows.
Versions
Section titled “Versions”GET /api/projects/{project_id}/canvas/versionsPOST /api/projects/{project_id}/canvas/versions/{version_id}/restoreEach version has its scope, tokens, model, status and plan basis. Restore makes it
current; your edits stay and are re-applied.
Mockups and images
Section titled “Mockups and images”GET /api/projects/{project_id}/canvas/mockups/{mockup_id}GET /api/projects/{project_id}/canvas/assets/{asset_id}?size=thumb|fullPOST /api/projects/{project_id}/canvas/assets (multipart "file")POST /api/projects/{project_id}/canvas/assets/from-file {"path": "docs/shot.png"}GET /api/projects/{project_id}/canvas/project-images?q=GET /api/projects/{project_id}/canvas/capturesPOST /api/projects/{project_id}/canvas/captures/reindexA mockup is served as a complete, sanitised document with a default-src 'none' CSP and its
images inlined. Show it only in an <iframe sandbox="">.
PATCH /api/projects/{project_id}/canvas/overlayDELETE /api/projects/{project_id}/canvas/overlay?target=&op={ "ops": [ {"target": "/boards/next:home", "op": "move", "value": {"x": 900, "y": 4100}}, {"target": "/pairs/home/changes/0/text", "op": "set", "value": "Cold-open first"}, {"target": "/notes/n1a2b3", "op": "add_note", "value": {"text": "Ask Sai", "fill": "signal", "x": 0, "y": 0}}, {"target": "/boards/changes:chat", "op": "hide", "remove": true} ]}Up to 100 edits per call, applied in order, all or none.
| Target | Ops |
|---|---|
/title, /subtitle, /timeline/lanes/{key}/title, /timeline/rows/{key}/title|subtitle | set |
/map/screens/{key}/pins/{n}/text, /pairs/{key}/changes/{i}/text | set |
/system_map/nodes/{key}/title|notes | set |
/pairs/{key}/now | set {asset_id, capture_id?, caption?} |
/boards/{board} (timeline, screen:{key}, now:{key}, next:{key}, changes:{key}, sys:{key}) | move, resize, hide, lock |
/notes/{id} | add_note (a sticky) |
/pairs | order (pair keys, first to last) |
Send "remove": true to revert an edit. "restore": true with the edit’s base_hash puts one
back exactly as it was (this is how undo restores an edit whose target is gone).
Generate
Section titled “Generate”GET /api/projects/{project_id}/canvas/estimate?scope=&map_type=&cap=&run_id=POST /api/projects/{project_id}/canvas/generateGET /api/projects/{project_id}/canvas/generations/{generation_id}?raw=1POST /api/projects/{project_id}/canvas/generations/{generation_id}/cancel{"scope": "all", "map_type": "screens", "cap": 600000, "model": "claude-native:claude-opus-5-5"}| Field | Notes |
|---|---|
scope | all, timeline, map, mockups, pairs, stale, or screen:{key} (with an optional note) |
cap | Budget tokens for this generation (default 400,000, up to 5,000,000) |
retry_of | A failed, partial or cancelled generation’s id: re-runs it, reusing finished stages |
Returns 202 with the generation; 409 while another generation of the canvas runs; 400
with code: "over_cap" or "over_run_budget" when the estimate doesn’t fit. The estimate
returns kind (swarm or standard), agent (a standard project’s agent) and model.
Export
Section titled “Export”POST /api/projects/{project_id}/canvas/exportRenders any missing mockup thumbnails before an export, and returns
{thumbs, missing, unavailable}, where unavailable says why when Playwright can’t render.
The PNG and PDF themselves are drawn in the browser.