Skip to content

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 ​

  • id string (uuid)

    Unique identifier for the template.

  • name string

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

  • short_description string

    One-line summary of what the template is for. Nullable.

  • description_html string

    Longer 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_type string

    Always page for page templates.

  • is_published boolean

    Whether the template is published. Defaults to false.

  • short_id string

    Short unique id that Plane generates when the template is created, for example k3x9p2. Filter on it with ?short_id=.

  • slug string

    URL-safe form of name. Plane regenerates it whenever the name changes.

  • project_id string (uuid)

    null on 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_data object

    The page seed. See The template_data object. null only if the seed row is missing.

  • created_at string (date-time)

    When the template was created.

  • updated_at string (date-time)

    When the template was last updated.

  • created_by_id string (uuid)

    The user who created the template.

  • updated_by_id string (uuid) or null

    The user who last updated the template. null until someone updates it.

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.

  • name string

    Title of the page created from the template. Required whenever you send template_data. Maximum 255 characters.

  • description_html string

    Body of the page, 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"}. Defaults to {}, which means no parent. See Parent validation.

  • 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. Pass back what you read rather than composing it by hand. Defaults to {}.

Response200
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
}

Endpoints ​

MethodPathDescription
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 version-4 UUID
  • project_id, a version-4 UUID
  • project_identifier, a string such as ENG

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 except the single-template GET 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 doesn't move existing project page templates. They stay on the project routes and can still be read, but update and delete return 409 templates_managed_at_workspace, and these workspace routes return 404 for them.

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.
  • 402 uses the problem+json body with code: "payment_required".

See Migrating from v1 for the full list.