Backlog API
Projects
Projects, their milestones and their status updates.
Base URLhttps://backlog.polder.work
A project is a body of work with a lead, a status, optional dates and a list of milestones. A project belongs to a
workspace, not to a team: every member of the workspace can read and change every project, guests included. A project
in another workspace answers 403.
The MCP server and the Projects screen do the same.
The project object
{
"id": 14,
"name": "Website relaunch",
"slug": "website-relaunch",
"summary": "New site before the summer",
"description": "<p>…</p>",
"status": "in_progress",
"health": "on_track",
"priority": 2,
"icon": "rocket",
"color": "#6366f1",
"lead": { "id": 5, "name": "Sanne", "email": "sanne@example.com", "isBot": false },
"starts_at": "2026-09-01",
"target_at": "2026-12-01",
"completed_at": null,
"deal_stage_id": null,
"deal_value": null,
"expected_close_at": null,
"created_at": "2026-08-30T09:12:44+00:00"
}
| Field | Description |
|---|---|
status |
deal, backlog, planned, in_progress, completed or canceled. A new project starts as backlog. deal means the project is still in the sales pipeline. |
health |
on_track, at_risk, off_track or null. Read-only: it is the health of the newest project update. |
priority |
0 (none) to 4. |
lead |
The lead as {id, name, email, isBot}, or null. |
starts_at, target_at |
Days (Y-m-d). |
completed_at |
Set when status becomes completed, cleared when it changes to anything else. |
deal_stage_id, deal_value, expected_close_at |
The sales side. Read-only here. |
description is rich text (HTML). It is sanitised on write, so tags that are not allowed are removed.
List projects
/api/v1/workspaces/{workspace}/projectsProjects of the workspace, ordered by name.
| Parameter | Description |
|---|---|
status |
Only projects with this status. |
q |
Case-insensitive match on a part of the name. |
page, per_page |
Paging. 50 per page by default, at most 200. |
curl "https://backlog.polder.work/api/v1/workspaces/7/projects?status=in_progress" \
-H "Authorization: Bearer $POLDER_TOKEN"
{
"data": [ { "id": 14, "name": "Website relaunch", "status": "in_progress", "…": "…" } ],
"meta": { "page": 1, "per_page": 50, "total": 1, "last_page": 1 }
}
Create a project
/api/v1/workspaces/{workspace}/projectsCreates a project and answers 201 with the project object. The history of the project starts with a created entry.
A project created with status: "deal" is placed in the first open stage of the sales pipeline.
Body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Up to 255 characters. The slug is made from it and is unique in the workspace. |
summary |
string or null | no | Up to 500 characters. |
description |
string or null | no | Rich text. |
status |
string | no | One of the statuses above. |
priority |
integer or null | no | 0 to 4. |
icon |
string or null | no | Up to 40 characters. |
color |
string or null | no | Up to 20 characters. |
lead_id |
integer or null | no | A user id; must be a member of this workspace. |
starts_at, target_at |
date or null | no | Y-m-d. |
curl https://backlog.polder.work/api/v1/workspaces/7/projects \
-H "Authorization: Bearer $POLDER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Website relaunch", "status": "planned", "lead_id": 5, "target_at": "2026-12-01"}'
Invalid input answers 422 with the messages per field.
Note:
healthcannot be set. Post a project update to change it.
Get a project
/api/v1/projects/{project}One project. 404 when it does not exist, 403 when it is in a workspace you are not a member of.
Change a project
/api/v1/projects/{project}Changes the fields you send; fields you leave out stay as they are. The fields are those of
Create a project, but name is optional. Send null to clear a nullable field.
Every changed field is written to the project's history under your name. Setting status to completed stamps
completed_at, and a status change can move a project to another stage of the sales pipeline. Answers 200 with the
project.
curl -X PATCH https://backlog.polder.work/api/v1/projects/14 \
-H "Authorization: Bearer $POLDER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"status": "completed"}'
The milestone object
{
"id": 31,
"project_id": 14,
"name": "Beta",
"description": null,
"target_at": "2026-10-15",
"position": 1
}
List milestones
/api/v1/projects/{project}/milestonesThe milestones of a project in plan order (position, then id), not in date order. Paged with page and per_page.
Create a milestone
/api/v1/projects/{project}/milestonesAdds a milestone and answers 201. Without position it is appended after the last one.
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | Up to 255 characters. |
description |
string or null | no | |
target_at |
date or null | no | Y-m-d. |
position |
integer or null | no | 0 or more. Places the milestone there; the others shift. |
curl https://backlog.polder.work/api/v1/projects/14/milestones \
-H "Authorization: Bearer $POLDER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "Beta", "target_at": "2026-10-15"}'
Change a milestone
/api/v1/milestones/{milestone}Changes the fields you send: name, description, target_at, position (same rules as above). Giving a position
moves the milestone and shifts the others. Answers 200 with the milestone.
Delete a milestone
/api/v1/milestones/{milestone}Deletes the milestone. Answers 204 without a body.
The project update object
{
"id": 88,
"project_id": 14,
"health": "at_risk",
"body": "The design review slipped a week.",
"progress": null,
"author": { "id": 5, "name": "Sanne", "email": "sanne@example.com", "isBot": false },
"edited_at": null,
"created_at": "2026-10-02T08:30:00+00:00"
}
Warning:
progressis currently alwaysnull. The percentage that was complete when the update was posted is stored, but not yet returned.
List project updates
/api/v1/projects/{project}/updatesThe status updates of a project, newest first. Paged with page and per_page.
Post a project update
/api/v1/projects/{project}/updatesPosts a status update as the owner of the token and answers 201. The health of the project becomes the health of the
newest update.
| Field | Type | Required | Description |
|---|---|---|---|
health |
string | yes | on_track, at_risk or off_track. |
body |
string or null | no | Up to 20000 characters. |
curl https://backlog.polder.work/api/v1/projects/14/updates \
-H "Authorization: Bearer $POLDER_TOKEN" \
-H "Content-Type: application/json" \
-d '{"health": "at_risk", "body": "The design review slipped a week."}'
Delete a project update
/api/v1/project-updates/{update}Deletes an update. Only its author or a workspace administrator may; anyone else gets 403. The project's health goes
back to that of the update before it, or to null when none is left. Answers 204.