Projects
Duplicating a project, and saving a project as a template to start others from. To list projects, use GET /api/public-v1/projects.
Duplicate a project
POST /api/v2/projects/:id/duplicate · beta
Copies a project: its settings, folders, lists and automations, and its tasks when asked.
The copy gets a new project code. Automations are copied switched off. Custom fields are shared with the copy, not duplicated. A personal list cannot be duplicated.
Up to 300 tasks are copied before the answer. More than that are copied afterwards as a job: the answer carries the job, and GET /api/v2/projects/:id/duplicate on the copy reports how far it has got.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | project.project_create. The project must be one the caller can open |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The project to copy. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | The copy's name, at most 255 characters. |
include.tasks | boolean | yes | Copy the tasks. |
include.assignees | boolean | yes | Keep the assignees of the copied tasks. |
include.dates | boolean | yes | Keep the dates of the project, its lists and its tasks. |
Any other key is refused.
Request
POST /api/v2/projects/<id>/duplicate
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"name": "Website (copy)",
"include": { "tasks": true, "assignees": false, "dates": false }
}Response
{
"status": true,
"statusText": "Project duplicated.",
"data": {
"project": { "_id": "<new project id>", "ProjectName": "Website (copy)", "ProjectCode": "WEB2" },
"counts": { "folders": 2, "lists": 5, "tasks": 48, "automations": 3 },
"notes": [{ "code": "automations_disabled", "count": 3 }],
"sharedFields": ["<custom field id>"],
"job": null
}
}| Field | Description |
|---|---|
project | The whole stored copy; the example shows some of its fields. |
counts | What was copied. tasks is 0 when the tasks are being copied as a job. |
notes | What was left out or changed, each with a code and a count or a name: tasks_left_out, private_lists_left, automations_skipped, automations_disabled, subfolder_moved_to_top. |
sharedFields | The ids of the custom fields now shared with the copy. |
job | null, or { id, status, total, processed, created } when the tasks are copied after the answer. |
Errors
| Status | When |
|---|---|
| 400 | The body is missing name or include, carries another key, a flag is not true or false, or the project is a personal list. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The person's role lacks the permission the route needs. |
| 404 | The project does not exist, is in the trash, or the caller cannot see it. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Read a duplicate's progress
GET /api/v2/projects/:id/duplicate · beta
Reports how far the tasks of a large copy have got.
Needs a project the caller can open. The path id is the copy that a POST /api/v2/projects/:id/duplicate made. Answers with data: the newest copy job that the caller started for that project, as id, status, total, processed and created, or null when there is none.
| Auth | Session or API token with the read scope |
| Token limited to projects | Refused |
| Permission | The project must be one the caller can open |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The copy, not the project it was copied from. |
Request
GET /api/v2/projects/<id>/duplicate
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Duplicate progress fetched.",
"data": {
"id": "<job id>",
"status": "processing",
"total": 1200,
"processed": 400,
"created": 400
}
}status is processing, done or failed. data is null when the caller started no copy job for that project.
Errors
| Status | When |
|---|---|
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the read scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. |
| 404 | The project does not exist, or the caller cannot see it. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Save a project as a template
POST /api/v2/projects/:id/template · beta
Saves a project's settings, folders, lists and, when asked, its tasks and automations as a template.
The template keeps no ids of the project it came from. Tasks start in the project's first status, with nothing ticked. A template holds at most 2000 tasks and a workspace at most 100 templates. A personal list cannot be saved.
A template is offered to everyone unless the project has a private list or everyone says otherwise. A template offered to everyone leaves private lists out. Automations are kept only when the caller may manage automations.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | project.project_create. The project must be one the caller can open |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The project to save. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | The template's name, at most 255 characters. |
include.tasks | boolean | yes | Keep the tasks. |
include.assignees | boolean | yes | Keep the assignees. |
include.dates | boolean | yes | Keep the dates, kept as distances from the project's start. |
include.automations | boolean | yes | Keep the automations. |
description | string | Up to 2000 characters. | |
everyone | boolean | Offer the template to everyone who can create projects. Defaults to true unless the project holds a private list. |
Any other key is refused.
Request
POST /api/v2/projects/<id>/template
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"name": "Website launch",
"include": { "tasks": true, "assignees": false, "dates": true, "automations": false }
}Response
{
"status": true,
"statusText": "Template saved.",
"data": {
"template": {
"_id": "<template id>",
"name": "Website launch",
"description": "",
"everyone": true,
"sourcePrivate": false,
"include": { "tasks": true, "assignees": false, "dates": true, "automations": false },
"counts": { "folders": 2, "lists": 5, "tasks": 48, "automations": 0 },
"statuses": [{ "key": "default_active", "name": "To do", "type": "default_active" }],
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"canManage": true
},
"notes": [{ "code": "private_lists_left", "count": 1 }]
}
}| Field | Description |
|---|---|
template | The saved template. |
notes | What was left out or changed, each with a code and a count or a name: tasks_left_out, private_lists_left, automations_skipped, subfolder_moved_to_top. |
Errors
| Status | When |
|---|---|
| 400 | The body is missing name or include, carries another key, has a value of the wrong type, or the project is a personal list; the project holds more than 2000 tasks and include.tasks is true; or the workspace already holds 100 templates. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The person's role lacks the permission the route needs. |
| 404 | The project does not exist, is in the trash, or the caller cannot open it. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
List project templates
GET /api/v2/projects/templates · beta
Lists the project templates the caller may use, by name.
Owners and admins see every template. Anyone else sees the templates offered to everyone and the ones they saved.
| Auth | Session or API token with the read scope |
| Token limited to projects | Refused |
| Permission | project.project_create |
Request
GET /api/v2/projects/templates
Authorization: Bearer <token>
companyid: <company id>Response
{
"status": true,
"statusText": "Templates fetched.",
"data": [
{
"_id": "<template id>",
"name": "Website launch",
"description": "",
"everyone": true,
"sourcePrivate": false,
"include": { "tasks": true, "assignees": false, "dates": true, "automations": false },
"counts": { "folders": 2, "lists": 5, "tasks": 48, "automations": 0 },
"statuses": [{ "key": "default_active", "name": "To do", "type": "default_active" }],
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"canManage": true
}
]
}data is the template as the caller may see it; canManage says whether the caller may change or delete it.
Paging
None. A workspace holds at most 100 templates.
Errors
| Status | When |
|---|---|
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the read scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The person's role lacks the permission the route needs. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Create a project from a template
POST /api/v2/projects/templates/:id/use · beta
Creates a project from a template, with its folders, lists and, when asked, its tasks.
The caller becomes a member of the new project. People who have left the workspace, and statuses and custom fields that no longer exist, are dropped. Dates are laid out from startDate; without it the project and its tasks have no dates.
The answer is the one of Duplicate a project.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | project.project_create |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The template. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | The project's name, at most 255 characters. |
include.tasks | boolean | yes | Use the tasks. |
include.assignees | boolean | yes | Use the assignees. |
include.dates | boolean | yes | Use the dates, kept as distances from the project's start. |
include.automations | boolean | yes | Use the automations. |
code | string | The project key, letters and digits, at most 10. It must not be taken. Defaults to a generated key. | |
isPrivate | boolean | Make the project private. Defaults to the template's own setting. | |
startDate | date | The project's first day. |
Any other key is refused.
Request
POST /api/v2/projects/templates/<id>/use
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{
"name": "Website relaunch",
"include": { "tasks": true, "assignees": false, "dates": true, "automations": false },
"startDate": "2026-11-02"
}Response
{
"status": true,
"statusText": "Project created from the template.",
"data": {
"project": {
"_id": "<new project id>",
"ProjectName": "Website relaunch",
"ProjectCode": "WEB3"
},
"counts": { "folders": 2, "lists": 5, "tasks": 48, "automations": 0 },
"notes": [],
"sharedFields": [],
"job": null
}
}data has the fields described under Duplicate a project.
Errors
| Status | When |
|---|---|
| 400 | The body is missing name or include, carries another key, has a value of the wrong type, or code is already taken. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. The person's role lacks the permission the route needs. |
| 404 | The template does not exist, or is not one the caller may use. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Change a project template
PATCH /api/v2/projects/templates/:id · beta
Changes a template's name, description or whether it is offered to everyone.
A template that holds a private list cannot be offered to everyone. Offering a template to everyone is for the person who saved it; owners and admins may also do it for one saved from a public project.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | The person who saved the template, an owner or an admin |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The template. |
Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | At most 255 characters. | |
description | string | Up to 2000 characters. | |
everyone | boolean | Offer the template to everyone who can create projects. |
Name at least one key. Any other key is refused.
Request
PATCH /api/v2/projects/templates/<id>
Authorization: Bearer <token>
companyid: <company id>
Content-Type: application/json
{ "name": "Website launch v2" }Response
{
"status": true,
"statusText": "Template updated.",
"data": {
"_id": "<template id>",
"name": "Website launch",
"description": "",
"everyone": true,
"sourcePrivate": false,
"include": { "tasks": true, "assignees": false, "dates": true, "automations": false },
"counts": { "folders": 2, "lists": 5, "tasks": 48, "automations": 0 },
"statuses": [{ "key": "default_active", "name": "To do", "type": "default_active" }],
"createdBy": "<user id>",
"createdAt": "2026-10-01T09:30:00.000Z",
"canManage": true
}
}data is the template as the caller may see it; canManage says whether the caller may change or delete it.
Errors
| Status | When |
|---|---|
| 400 | The body names nothing to change, carries another key, has a value of the wrong type, or offers a template that holds a private list to everyone. |
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. |
| 404 | The template does not exist, or is not one the caller may use. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
Delete a project template
DELETE /api/v2/projects/templates/:id · beta
Deletes a template and the task rows it kept. Projects made from it are not affected.
Allowed for the person who saved the template and for owners and admins; a template the caller may not see answers 404 and one they may see but not manage answers 403. The template is marked deleted and so are the task rows kept with it. Answers with statusText Template deleted. and no data.
| Auth | Session or API token with the write scope |
| Token limited to projects | Refused |
| Permission | The person who saved the template, an owner or an admin |
Path parameters
| Name | Type | Description |
|---|---|---|
id | id | The template. |
Request
DELETE /api/v2/projects/templates/<id>
Authorization: Bearer <token>
companyid: <company id>Response
{ "status": true, "statusText": "Template deleted." }Errors
| Status | When |
|---|---|
| 401 | No token, a token that is invalid, expired or revoked, or no valid companyid header. |
| 403 | The token lacks the write scope, or its person is no longer a member of the workspace. A token limited to projects is refused here. |
| 404 | The template does not exist, or is not one the caller may use. |
| 429 | Too many requests from this address. Wait retryAfter seconds and send it again. |
