Skip to content

Projects

Projects group tasks and documents around a goal, inside a space. These endpoints act on your own projects only: an id belonging to anyone else returns 404 Not Found.

Returns every project you haven’t archived.

GET /api/projects

Filter by space with one query parameter:

Name Type Required Description
spaceId string No Only projects in this space

Archived projects never appear in this list. Each project includes its space summary and a _count object with the numbers of tasks and documents. Projects come back ordered by sortOrder.

A bare JSON array of projects:

[
{
"id": "b7d3e9a1-5c02-4f47-9a86-1d6b0e4c8a53",
"userId": "6f0d2a9b-1c74-4e8f-8a3b-5c9d0e2f6a71",
"spaceId": "0e5a7c3b-2f16-4d98-b7a4-8c1e3f5d9b02",
"name": "Website refresh",
"description": "Rework the marketing site.",
"color": "#10B981",
"icon": "globe",
"status": "in_progress",
"priority": 2,
"targetDate": "2026-12-01T13:00:00.000Z",
"archived": false,
"sortOrder": 0,
"createdAt": "2026-09-28T22:40:11.000Z",
"updatedAt": "2026-09-30T00:15:42.000Z",
"space": { "id": "0e5a7c3b-2f16-4d98-b7a4-8c1e3f5d9b02", "name": "Work", "color": "#3B82F6", "icon": "briefcase" },
"_count": { "tasks": 6, "documents": 2 }
}
]

The list isn’t paginated; it returns every matching project at once.

Code When
200 OK the list returned
401 Unauthorized no valid session or API key

Creates one project, optionally inside a space.

POST /api/projects

Send these fields in the JSON body:

Name Type Required Description
name string Yes Project name, 1–200 characters
description string No Longer text
color string No Colour such as #10B981
icon string No Icon name
spaceId string No Id of one of your spaces; without it the project has no space
priority integer No Sort priority
targetDate string No ISO 8601 timestamp you’re aiming for
autoSchedule boolean No Let the scheduler place this project’s tasks; defaults to true

The spaceId must name a space you own. New projects start with status backlog, archived false and sortOrder 0.

The new project comes back with 201 Created:

{
"id": "b7d3e9a1-5c02-4f47-9a86-1d6b0e4c8a53",
"userId": "6f0d2a9b-1c74-4e8f-8a3b-5c9d0e2f6a71",
"spaceId": "0e5a7c3b-2f16-4d98-b7a4-8c1e3f5d9b02",
"name": "Website refresh",
"description": "Rework the marketing site.",
"color": "#10B981",
"icon": "globe",
"status": "backlog",
"priority": null,
"targetDate": null,
"archived": false,
"sortOrder": 0,
"createdAt": "2026-09-28T22:40:11.000Z",
"updatedAt": "2026-09-28T22:40:11.000Z"
}

The response is the project row on its own; the space and _count fields appear in the project list and in the single-project response.

Code When
201 Created the project was created
400 Bad Request the body failed validation (Validation failed), or spaceId named a record you don’t own (spaceId not found)
401 Unauthorized no valid session or API key

Returns one project with its space, open tasks and documents.

GET /api/projects/{id}

Set {id} to the project’s id.

The project comes back with its related records:

{
"id": "b7d3e9a1-5c02-4f47-9a86-1d6b0e4c8a53",
"userId": "6f0d2a9b-1c74-4e8f-8a3b-5c9d0e2f6a71",
"spaceId": "0e5a7c3b-2f16-4d98-b7a4-8c1e3f5d9b02",
"name": "Website refresh",
"description": "Rework the marketing site.",
"color": "#10B981",
"icon": "globe",
"status": "in_progress",
"priority": 2,
"targetDate": "2026-12-01T13:00:00.000Z",
"archived": false,
"sortOrder": 0,
"createdAt": "2026-09-28T22:40:11.000Z",
"updatedAt": "2026-09-30T00:15:42.000Z",
"space": { "id": "0e5a7c3b-2f16-4d98-b7a4-8c1e3f5d9b02", "name": "Work", "color": "#3B82F6", "icon": "briefcase" },
"tasks": [
{
"id": "9c1f4b2e-7d83-4c6a-9e50-3f8a2b7d1c04",
"title": "Write project brief",
"status": "todo",
"priority": "high",
"dueAt": "2026-10-07T13:00:00.000Z",
"estimateMinutes": 90,
"labels": [
{ "id": "d2a6f8c4-9b31-4e57-8c02-7a4d1e6b3f89", "name": "writing", "color": "#F59E0B" }
]
}
],
"documents": [
{
"id": "c9f4a1b7-6e28-4d50-a3c9-8b5e0d7f2a63",
"title": "Brief template",
"docType": "reference",
"url": "https://example.com/brief-template",
"createdAt": "2026-09-28T23:05:00.000Z"
}
]
}

tasks holds at most 50 of the project’s open tasks — completed, cancelled and archived tasks are excluded — ordered by priority (highest first) and then due date; each entry is a task object with its labels, as on the Tasks page. documents lists the project’s documents in sortOrder order.

Code When
200 OK the project returned
401 Unauthorized no valid session or API key
404 Not Found no project with that id belongs to you (Project not found)

Changes fields of one project. Omit the fields you want to keep.

PATCH /api/projects/{id}

Send only the fields to change in the JSON body:

Name Type Required Description
name string No Project name, 1–200 characters
description string No Longer text
color string No Colour such as #10B981
icon string No Icon name
spaceId string or null No Move to one of your spaces, or null for no space
status backlog | planned | in_progress | completed | cancelled | archived No Project status
priority integer No Sort priority
targetDate string No ISO 8601 timestamp; send "" to clear it
archived boolean No Archive the project or bring it back
autoSchedule boolean No Let the scheduler place this project’s tasks; false treats them all as manual
sortOrder number No Position in the project list

Setting archived to true does the same thing as the delete endpoint.

The updated project comes back with its space summary:

{
"id": "b7d3e9a1-5c02-4f47-9a86-1d6b0e4c8a53",
"userId": "6f0d2a9b-1c74-4e8f-8a3b-5c9d0e2f6a71",
"spaceId": "0e5a7c3b-2f16-4d98-b7a4-8c1e3f5d9b02",
"name": "Website refresh",
"description": "Rework the marketing site.",
"color": "#10B981",
"icon": "globe",
"status": "completed",
"priority": 2,
"targetDate": "2026-12-01T13:00:00.000Z",
"archived": false,
"sortOrder": 0,
"createdAt": "2026-09-28T22:40:11.000Z",
"updatedAt": "2026-09-30T00:15:42.000Z",
"space": { "id": "0e5a7c3b-2f16-4d98-b7a4-8c1e3f5d9b02", "name": "Work", "color": "#3B82F6", "icon": "briefcase" }
}

Only the fields you send change; the rest keep their old values.

Code When
200 OK the project was updated
400 Bad Request the body failed validation (Validation failed), or spaceId named a record you don’t own (spaceId not found)
401 Unauthorized no valid session or API key
404 Not Found no project with that id belongs to you (Project not found)

Marks one project as archived. The project and its tasks stay in the database.

DELETE /api/projects/{id}

No body is needed. Add ?permanent=true to delete the project for good instead: its tasks and documents are kept but become unassigned. Permanent delete can’t be undone.

The endpoint confirms the change:

{
"success": true
}

The project’s archived flag becomes true, which hides it from the project list. Its tasks keep their projectId, so GET /api/projects/{id} still shows them.

Code When
200 OK the project was archived
401 Unauthorized no valid session or API key
404 Not Found no project with that id belongs to you (Project not found)