Copy a project template
Copy a published project template into this workspace as a new template that the workspace owns. The source can live in this workspace or in any other one, as long as it is published. The source id goes in the body instead of the path, because the source usually isn't a template that this workspace's routes can address.
The response is the new template in full, with 201. Edit or use it like any other template in the workspace. Later changes to the source don't reach the copy.
Path parameters
slug:requiredstringThe workspace to copy the template into. It appears in your Plane URLs. In https://app.plane.so/my-team/projects/, the slug is my-team.
Body parameters
template_id:requiredstring (uuid)The id of the project template to copy. It must have is_published: true. An unknown id returns 404, and so does the id of an unpublished template, even one in this workspace.
Response shaping
fields:optionalstringComma-separated list of fields to return. Fields you don't request are left out of the response instead of coming back as null, so a missing key means you didn't ask for it and null means the value is null. id is always included, whether or not you name it.
Pass all to get every requestable field. An unknown field name returns 400 with the list of valid names and the closest match, so a typo is caught instead of being silently ignored.
Requestable here: category_ids, created_at, created_by_id, description_html, id, is_published, is_verified, name, short_description, short_id, slug, template_data, template_type, updated_at, updated_by_id.
See Sparse fields.
Scopes
templates.projects:write
Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_request | template_id is missing or isn't a valid UUID. |
401 | unauthorized | Missing or invalid credentials. |
402 | payment_required | Project templates aren't in your plan, or the feature is switched off for this workspace. |
403 | forbidden | Your role or token scope can't create project templates in this workspace. |
404 | not_found | No such workspace, or no published project template has this id. |
404 | not_found | The source is in another workspace and its cover image is stored in Plane. |
406 | not_acceptable | The Accept header asks for a representation the API can't produce. |
409 | governance_migration_in_progress | The workspace is migrating to workspace governance. Writes are blocked until it finishes, so retry later. |
413 | payload_too_large | The request body is over the size limit. |
415 | unsupported_media_type | The Content-Type isn't one this endpoint accepts. |
429 | rate_limited | Throttled. Honor the Retry-After header before retrying. |
curl -X POST \
"https://api.plane.so/api/v2/workspaces/my-team/project-templates/copy/" \
-H "X-Api-Key: $PLANE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"template_id": "8c3f6a1d-2e7b-4d95-a4c0-6f1b9e3d7a28"
}'import requests
response = requests.post(
"https://api.plane.so/api/v2/workspaces/my-team/project-templates/copy/",
headers={"X-Api-Key": "your-api-key"},
json={"template_id": "8c3f6a1d-2e7b-4d95-a4c0-6f1b9e3d7a28"},
)
print(response.json()["id"])const response = await fetch(
"https://api.plane.so/api/v2/workspaces/my-team/project-templates/copy/",
{
method: "POST",
headers: {
"X-Api-Key": "your-api-key",
"Content-Type": "application/json",
},
body: JSON.stringify({ template_id: "8c3f6a1d-2e7b-4d95-a4c0-6f1b9e3d7a28" }),
},
);
const data = await response.json();{
"id": "2f9d4b7e-6a13-4c58-8e21-b0d7c5a3f946",
"name": "Product launch",
"short_description": "Phases and states for shipping a new product",
"description_html": "<p></p>",
"template_type": "project",
"is_published": false,
"is_verified": false,
"short_id": "w4n7ub",
"slug": "product-launch",
"category_ids": [],
"template_data": {
"id": "7e1b5c9a-3d46-4f82-b9a0-1c6e8d2f4b73",
"name": "Product launch",
"description": "From beta to general availability",
"network": 2,
"default_assignee": {},
"project_lead": {},
"logo_props": {},
"cover_asset": "",
"module_view": true,
"cycle_view": true,
"issue_views_view": true,
"page_view": true,
"intake_view": true,
"is_time_tracking_enabled": false,
"is_issue_type_enabled": false,
"is_project_updates_enabled": true,
"is_epic_enabled": false,
"is_workflow_enabled": false,
"is_milestone_enabled": false,
"guest_view_all_features": false,
"timezone": "UTC",
"archive_in": 0,
"close_in": 0,
"states": [
{
"id": "f3a8d1c6-9b25-4e70-8d43-5c2a7e9b1f08",
"name": "Planned",
"color": "#a3a3a3",
"group": "unstarted",
"default": true,
"sequence": 15000
},
{
"id": "4b9e2f7a-1c58-4d36-a7e0-9f3d6b1c8e25",
"name": "Launched",
"color": "#16a34a",
"group": "completed",
"default": false,
"sequence": 25000
}
],
"priority": "medium",
"project_state": {},
"start_date": null,
"target_date": null,
"labels": [],
"workflows": {},
"estimates": {},
"workitem_types": {},
"epics": {},
"members": [],
"intake_settings": {
"is_form_enabled": true,
"is_email_enabled": false,
"is_in_app_enabled": true
},
"milestones": {},
"modules": {},
"recurring_work_items": {},
"automations": {},
"workitems": []
},
"created_at": "2026-02-03T16:45:12.904117Z",
"updated_at": "2026-02-03T16:45:12.904117Z",
"created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
"updated_by_id": null
}{
"type": "not_found",
"code": "not_found",
"detail": "No published project template matches that id."
}What the copy keeps
The copy is a new template in this workspace with a new id and short_id. From the source it keeps:
nameandshort_description.- The whole
template_dataseed, except the keys listed below. - The cover. Plane reuses an external cover URL as is and duplicates a cover image stored in Plane as a new asset. It looks for that image in this workspace, so copying such a template from another workspace returns
404and creates nothing.
What the copy drops
description_htmlresets to<p></p>.is_publishedisfalse,is_verifiedisfalse, andcategory_idsis empty.template_data.default_assignee,project_lead, andproject_statereset to{}, andmembersresets to[]. Users and lifecycle states are specific to the source workspace.- The default value of every
RELATIONproperty inworkitem_typesandepicsresets to[]. template_data.workitemsis empty. The bundled work items stay with the source. If you can read the source template, send itsworkitemsin an update of the copy.
Naming
When this workspace already has a project template whose name starts with the source's name, the copy takes the newest such template's name plus (copy). Copying Product launch twice gives Product launch and then Product launch (copy). template_data.name follows the same rule against the workspace's other project seeds.

