Skip to content

Create a workspace page template ​

POST/api/v2/workspaces/{slug}/page-templates/

Create a page template that belongs to the whole workspace. The request has two parts. The top-level fields describe the template in the picker, and template_data is the page that the template creates.

The template stays workspace-level for its whole life. To create one that belongs to a project, use Create a project page template.

Path Parameters ​

slug:requiredstring

The workspace slug. It appears in your Plane URLs, so in https://app.plane.so/my-team/projects/ the slug is my-team.

Body Parameters ​

name:requiredstring

Display name of the template, shown in the template picker. Maximum 255 characters.

template_data:requiredobject

The page seed. Keys:

  • name (string, required). Title of the page created from the template. Maximum 255 characters.
  • description_html (string). Page body as HTML. Defaults to <p></p>.
  • color (string). Page color, for example #3f76ff. Defaults to an empty string.
  • parent (object). The page that new pages nest under, as {"id", "project_id", "project_identifier"}. All three keys are required when parent is not empty. Defaults to {}.
  • view_props (object). Page display settings, for example {"full_width": false}. Defaults to {}.
  • logo_props (object). Editor-owned descriptor for the page icon or emoji. Defaults to {}.

See Parent validation.

short_description:optionalstring

One-line summary of what the template is for. Nullable. null and omission are both stored as an empty string.

description_html:optionalstring

Longer description of the template itself, as HTML. Defaults to <p></p>. This is not the page body, which goes in template_data.description_html.

is_published:optionalboolean

Whether the template is published. Defaults to false.

Response shaping ​

fields:optionalstring

Comma-separated list of fields to return. Unrequested keys are omitted from the response, not returned as null, so absent means "not requested" and null means "actually null". id always comes back whether or not you name it.

Pass all for every requestable field. An unknown name is a 400 that lists the valid set and suggests the closest match, so a typo can't silently cost you the saving.

Requestable here: created_at, created_by_id, description_html, id, is_published, name, project_id, short_description, short_id, slug, template_data, template_type, updated_at, updated_by_id.

See Sparse fields.

Scopes ​

templates.pages:write

Errors ​

StatusCodeCause
400invalid_requestname, template_data, or template_data.name is missing, a value is over its length limit, or parent is malformed.
401unauthorizedMissing or invalid credentials.
402payment_requiredPage templates aren't in your plan, or the feature is switched off for this workspace.
403forbiddenYour role or token scope can't create workspace page templates.
404not_foundNo such workspace, or it's outside your tenant.
406not_acceptableThe Accept header asks for a representation the API can't produce.
409governance_migration_in_progressThe workspace is migrating to workspace governance. Writes are blocked until it finishes, so retry later.
413payload_too_largeThe request body is over the size limit.
415unsupported_media_typeThe Content-Type isn't one this endpoint accepts.
429rate_limitedThrottled. Honor the Retry-After header before retrying.
Create a workspace page template
bash
curl -X POST \
  "https://api.plane.so/api/v2/workspaces/my-team/page-templates/" \
  -H "X-Api-Key: $PLANE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "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_data": {
    "name": "Weekly sync notes",
    "description_html": "<h2>Agenda</h2><ul><li><p>Updates</p></li><li><p>Blockers</p></li></ul>",
    "color": "#3f76ff",
    "view_props": { "full_width": false },
    "logo_props": { "in_use": "emoji", "emoji": { "value": "128221" } }
  }
}'
Response201
json
{
  "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
}

A parent needs all three keys

The API checks template_data.parent for shape only. A parent with only an id returns 400 invalid_request. Send id, project_id, and project_identifier together, or leave parent out.