Project templates overview
A project template describes a project before it exists: its feature toggles, work item states, labels, work item types, estimates, intake settings, and a list of starter work items. Use a project template to create a real project from it.
Project templates belong to the workspace. There is no project-level variant, because a project template describes a project rather than living in one.
Learn more about project templates
The project template object
Attributes
idstring (uuid)Unique identifier for the template. This is the id that
useandcopytake.namestringDisplay name of the template, shown in the template picker. Maximum 255 characters.
short_descriptionstringOne-line summary of what the template is for. Nullable.
description_htmlstringLonger description of the template itself, as HTML. The description of the project it creates is
template_data.description.template_typestringAlways
projectfor project templates.is_publishedbooleanWhether the template is published. Defaults to
false. Only published templates can be pulled into a workspace with Copy a project template.is_verifiedbooleanWhether Plane has verified the template. Plane sets it, so you can filter on it but not write it.
short_idstringShort unique id that Plane generates when the template is created, for example
p7m2qa. Filter on it with?short_id=.slugstringURL-safe form of
name. Plane regenerates it whenever the name changes.category_idsarray of string (uuid)The template categories the template is tagged with. Read-only here. Filter on them with
?category_id=or?category_id__in=.template_dataobjectThe project seed and its bundled work items. See The template_data object.
nullonly if the seed row is missing.created_atstring (date-time)When the template was created.
updated_atstring (date-time)When the template was last updated.
created_by_idstring (uuid)The user who created the template.
updated_by_idstring (uuid)The user who last updated the template.
The template_data object
template_data is the project the template creates. Every key comes back on read, with the model default when you never set it. Ids inside it, such as a state's id, are your own identifiers for the template. use maps them onto the rows it creates, so point a work item seed's state.id at an entry in states.
idstring (uuid)Id of the seed row. Read-only, and different from the template's
id.namestringName of the project the template describes. Required whenever you send
template_data. Maximum 255 characters, and unique among the workspace's project templates.descriptionstringDescription of the project.
networkintegerProject visibility.
0is private to members,2is visible to the whole workspace. Defaults to2.default_assignee,project_leadobjectStored as sent. Defaults to
{}.logo_propsobjectEditor-owned descriptor for the project icon. Defaults to
{}.cover_assetstringCover image, as an external URL or a Plane asset path. An empty string means no cover.
module_view,cycle_view,issue_views_view,page_viewbooleanFeature toggles for modules, cycles, views, and pages. Each defaults to
true.intake_view,is_time_tracking_enabled,is_issue_type_enabled,is_project_updates_enabled,is_epic_enabled,is_workflow_enabled,is_milestone_enabled,guest_view_all_featuresbooleanFeature toggles for intake, time tracking, work item types, project updates, epics, workflows, milestones, and guest access to all features. Each defaults to
false.timezonestringIANA time zone, for example
America/New_York. Defaults toUTC.archive_in,close_inintegerMonths before completed work items are auto-archived and before stale work items are auto-closed. From
0to12, where0turns the automation off. Defaults to0.statesarray of objectThe project's work item states. Each entry needs
id(a UUID you choose),name,color,sequence(a number), andgroup(one ofbacklog,unstarted,started,completed,cancelled, ortriage).descriptionanddefaultare optional.prioritystringProject priority. One of
none,low,medium,high, orurgent. Defaults tonone.project_stateobjectThe project's lifecycle state, as
{"id", "name", "group"}. Defaults to{}.start_date,target_datestring (date-time)Planned dates. Nullable.
labelsarray of objectWork item labels, each with
id,name, andcolor(at most 7 characters, for example#3f76ff).estimatesobjectAn estimate as
{"id", "name", "type", "points"}, where each point hasid,key(0 to 12), andvalue.workitem_typesarray of objectWork item type definitions, each with
id,name,logo_props,is_epic, andproperties.description,is_default, andis_activeare optional.epicsobjectThe epic type, with
id,name, andproperties.membersarray of objectMembers as
{"id"}entries. Defaults to[].intake_settingsobjectis_in_app_enabled,is_email_enabled, andis_form_enabledbooleans.workflows,milestones,modules,recurring_work_items,automationsobject or arrayStored as sent. Each defaults to
{}.workitemsarray of objectThe starter work items, in creation order. Each has
name(required),description_html,priority,state({"id", "name", "group"}),assignees,labels,type,modules, andproperties. See Bundled work items.
{
"id": "5b7e3c1a-9d24-4f68-b5a0-2e8c6d4f1b97",
"name": "Service launch",
"short_description": "States, labels, and starter work items for a new service",
"description_html": "<p>Use this for every new backend service.</p>",
"template_type": "project",
"is_published": false,
"is_verified": false,
"short_id": "p7m2qa",
"slug": "service-launch",
"category_ids": [],
"template_data": {
"id": "e4a9c2f7-1b38-4d5e-9f60-7a2c8b3d1e45",
"name": "Service project",
"description": "Bootstraps a new backend service",
"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": false,
"is_time_tracking_enabled": false,
"is_issue_type_enabled": false,
"is_project_updates_enabled": false,
"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": "a1f4c7e2-5b8d-4e19-9c63-2f7a0d4b8e15",
"name": "Backlog",
"color": "#a3a3a3",
"group": "backlog",
"default": true,
"sequence": 15000
},
{
"id": "c8e3f1b5-7a24-4d96-b0e1-4a6d8c2f9b37",
"name": "Done",
"color": "#16a34a",
"group": "completed",
"default": false,
"sequence": 25000
}
],
"priority": "high",
"project_state": {},
"start_date": null,
"target_date": null,
"labels": [
{
"id": "d4b7a2e9-1f63-4c85-9e02-6b3d8f1a7c54",
"name": "infra",
"color": "#3f76ff"
}
],
"workflows": {},
"estimates": {},
"workitem_types": {},
"epics": {},
"members": [],
"intake_settings": {},
"milestones": {},
"modules": {},
"recurring_work_items": {},
"automations": {},
"workitems": [
{
"name": "Set up CI",
"description_html": "<p>Build, test, and deploy on every merge.</p>",
"priority": "high",
"state": {
"id": "a1f4c7e2-5b8d-4e19-9c63-2f7a0d4b8e15",
"name": "Backlog",
"group": "backlog"
},
"assignees": [],
"labels": [
{
"id": "d4b7a2e9-1f63-4c85-9e02-6b3d8f1a7c54",
"name": "infra",
"color": "#3f76ff"
}
],
"type": {},
"modules": [],
"properties": []
}
]
},
"created_at": "2026-01-14T09:22:41.478363Z",
"updated_at": "2026-01-14T09:22:41.478363Z",
"created_by_id": "16c61a3a-512a-48ac-b0be-b6b46fe6f430",
"updated_by_id": null
}Endpoints
| Method | Path | Description |
|---|---|---|
GET | /api/v2/workspaces/{slug}/project-templates/ | List project templates |
GET | /api/v2/workspaces/{slug}/project-templates/{pk}/ | Get a project template |
POST | /api/v2/workspaces/{slug}/project-templates/ | Create a project template |
PATCH | /api/v2/workspaces/{slug}/project-templates/{pk}/ | Update a project template |
DELETE | /api/v2/workspaces/{slug}/project-templates/{pk}/ | Delete a project template |
POST | /api/v2/workspaces/{slug}/project-templates/copy/ | Copy a published project template |
POST | /api/v2/workspaces/{slug}/project-templates/{pk}/use/ | Create a project from a template |
Shape checks
The JSON keys inside template_data are free-form in storage, so create and update check their shape before saving. states, project_state, labels, estimates, workitem_types, epics, intake_settings, and members are checked against the shapes listed above, and so are the state, type, assignees, labels, modules, and properties of every work item seed. A failure returns 400 invalid_request and saves nothing. The detail is Invalid template data. for the project keys, or Invalid work item template at index N. for the seed at position N in workitems.
The checks cover shape only. They don't confirm that a referenced user, label, or state exists anywhere in Plane.
Bundled work items
template_data.workitems is a list that you always write as a whole:
- On create, the list you send becomes the template's work items. Omit it for none.
- On update, sending
template_datareplaces the stored list with the one you send. The old seeds are deleted, never merged. If yourtemplate_datahas noworkitemskey, the template ends up with no work items. - An update without
template_dataleaves the work items alone.
To add one work item, read the template, append to the workitems you got back, and send the full template_data.
Updating template_data
The other keys in template_data merge on update. A key you send overwrites the stored value, and a key you omit keeps it, with three exceptions:
workitemsis replaced as described above.membersresets to[]when you omit it.cover_assetresets to an empty string when you omit it or sendnull.
template_data.name is required whenever you send template_data, even when you aren't changing it.
Copy and use
- Copy a project template pulls a published template, from this workspace or another one, into this workspace as a new unpublished template. It returns the new template.
- Create a project from a template creates a real project in this workspace from one of this workspace's templates. It returns the new project.
Feature gating
Project templates are a paid feature. When the workspace's plan doesn't include them, or the feature is switched off, every endpoint here returns 402 payment_required. See Errors.
Workspace governance doesn't block these routes. While a governance migration runs, every write in the workspace, including these, returns 409 governance_migration_in_progress.
Response shaping
Every read accepts ?fields= for sparse responses. See Sparse fields.
List rows leave out description_html and template_data by default. template_data carries the whole project seed and every bundled work item, so it is the expensive part of a row. Name either field in ?fields=, or pass ?fields=all, to get it on list rows. A single-template response always includes both. Errors follow the shared problem+json contract.
Changed from v1
- The routes move from
/api/v1/workspaces/{slug}/projects/templates/to/api/v2/workspaces/{slug}/project-templates/. usetakes the template id in the path, at/project-templates/{pk}/use/. v1 tooktemplate_idin the body of/projects/templates/use/.copyreturns the full new template with201. v1 returned only{"template_id": ...}.- The list is paginated, filterable, and searchable. v1 returned every template in one array.
template_datadoesn't carry aworkspacekey.
See Migrating from v1 for the full list.

