Workspace page templates overview
A page template is a reusable starting point for a page. It stores a title, an HTML body, and display settings that Plane copies into a new page. Workspace page templates belong to the whole workspace. Project page templates belong to one project and have their own routes.
The two sets never overlap. A template stays in the scope it was created through, and no write moves it. A workspace template's id returns 404 on the project routes, and a project template's id returns 404 here.
Learn more about page templates
The page template object
Attributes
idstring (uuid)Unique identifier for the template.
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 body of the page that the template creates is
template_data.description_html, not this field.template_typestringAlways
pagefor page templates.is_publishedbooleanWhether the template is published. Defaults to
false.short_idstringShort unique id that Plane generates when the template is created, for example
k3x9p2. Filter on it with?short_id=.slugstringURL-safe form of
name. Plane regenerates it whenever the name changes.project_idstring (uuid)nullon a workspace page template. A project page template carries its project's id. Read-only, because the route you create a template through fixes its scope.template_dataobjectThe page seed. 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 holds what a new page starts with. Every key comes back on read, with its default when you never set it.
namestringTitle of the page created from the template. Required whenever you send
template_data. Maximum 255 characters.description_htmlstringBody of the page, as HTML. Defaults to
<p></p>.colorstringPage color, for example
#3f76ff. Defaults to an empty string.parentobjectThe page that new pages nest under, as
{"id", "project_id", "project_identifier"}. Defaults to{}, which means no parent. See Parent validation.view_propsobjectPage display settings, for example
{"full_width": false}. Defaults to{}.logo_propsobjectEditor-owned descriptor for the page icon or emoji. Pass back what you read rather than composing it by hand. Defaults to
{}.
{
"id": "3d8b2f4e-6a1c-4e57-9b02-7c5d1e8f4a36",
"name": "Weekly sync",
"short_description": "Agenda and notes for the weekly team sync",
"description_html": "<p>Use this for the Monday team sync.</p>",
"template_type": "page",
"is_published": false,
"short_id": "k3x9p2",
"slug": "weekly-sync",
"project_id": null,
"template_data": {
"name": "Weekly sync notes",
"description_html": "<h2>Agenda</h2><ul><li><p>Updates</p></li><li><p>Blockers</p></li></ul>",
"color": "#3f76ff",
"parent": {},
"view_props": {
"full_width": false
},
"logo_props": {
"emoji": {
"value": "128221"
},
"in_use": "emoji"
}
},
"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}/page-templates/ | List workspace page templates |
GET | /api/v2/workspaces/{slug}/page-templates/{pk}/ | Get a workspace page template |
POST | /api/v2/workspaces/{slug}/page-templates/ | Create a workspace page template |
PATCH | /api/v2/workspaces/{slug}/page-templates/{pk}/ | Update a workspace page template |
DELETE | /api/v2/workspaces/{slug}/page-templates/{pk}/ | Delete a workspace page template |
Parent validation
The API checks the shape of template_data.parent and nothing else. A non-empty parent must carry all three keys:
id, a UUIDproject_id, a UUIDproject_identifier, a string such asENG
A partial object, for example one with only id, returns 400 invalid_request with errors entries under template_data.parent. The API does not look up the page or the project, so it accepts a well-formed reference to a page that doesn't exist. Send {} or omit parent for no parent.
Updating template_data
template_data on a PATCH replaces the whole seed. Send every key you want to keep, because each omitted key goes back to its default: description_html to <p></p>, color to an empty string, and parent, view_props, and logo_props to {}. template_data.name is required whenever you send template_data.
A PATCH without template_data changes only the top-level fields you send and leaves the seed alone.
Feature gating
Page 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
Workspace governance doesn't block the workspace routes. In a workspace with governance turned on, these are the routes for creating and changing page templates, because project page template writes return 409 templates_managed_at_workspace. Turning governance on moves existing project page templates to the workspace, so they show up in this list.
While the governance migration runs, every write in the workspace, including these, returns 409 governance_migration_in_progress. Reads keep working.
Response shaping
Every read accepts ?fields= for sparse responses. See Sparse fields.
List rows leave out description_html and template_data by default, because both carry HTML. Name them in ?fields=, or pass ?fields=all, to get them on list rows. A single-template response always includes them. Errors follow the shared problem+json contract.
Changed from v1
- The routes move from
/api/v1/workspaces/{slug}/pages/templates/to/api/v2/workspaces/{slug}/page-templates/. - The list is paginated, filterable, and searchable. v1 returned every template in one array.
402uses the problem+json body withcode: "payment_required".
See Migrating from v1 for the full list.

