Creating pages from templates

Learn how to apply data source templates to pages created in the Notion API.

Overview

Database templates save time when adding a new page to a data source. Instead of building manually from a blank page, templates accelerate your workflows by providing a blueprint for the page's properties and content.

For example, a bug tracking database can have templates for various types of bugs, like "Urgent Production Bug" and "User Interface (UI) Bug".

The Notion app can be used to create and manage templates, and designate one as the "default" template:

To take advantage of templates when creating pages in the API, the three main steps are:

  1. Identify the template to use. Use the List data source templates endpoint, or manually navigate to the template in the Notion app and get its ID. Skip this step if you want to apply the data source's "default" template.
  2. Create page with the chosen template. Provide a template[type] of default, or of template_id alongside a template[template_id], to the Create a page API to kick off the process of "duplicating" a template into a new page.
    1. Remember to use a parent[type] of data_source_id and provide a parent[data_source_id] when creating a page under a data source.
    2. Store the ID of the newly created page in your app's backend storage systems. This will be necessary in the next step, since the returned page is momentarily blank until the template finishes applying.
  3. Wait for template processing to complete. If your integration needs to perform additional steps once a template has finished applying to a page and it's ready for use, wait for Notion's systems to populate the page content before proceeding.
    1. Register an handler for integration webhooks that listens to page.created and page.content_updated events and uses the Retrieve block children API to confirm the page contents are populated.

Step 1: Identify the template to use

For integrations using the Notion API, use the List data source templates endpoint to retrieve a list of template IDs and titles:

curl --request GET \
     --url 'https://api.notion.com/v1/data_sources/b55c9c91-384d-452b-81db-d1ef79372b75/templates' \
     -H 'Notion-Version: 2025-09-03' \
     -H 'Authorization: Bearer '"$NOTION_API_KEY"''

The API response includes a similar set of information as the Notion app displays in the screenshot above:

{
  "templates": [
    {
      "id": "a5da15f6-b853-455d-8827-f906fb52db2b",
      "name": "New Generic Task",
      "is_default": true
    },
    {
      "id": "9cc74169-8dd7-4104-8b36-ed952ac44bd0",
      "name": "New UI Task",
      "is_default": false
    },
    {
      "id": "f2d298e3-efeb-4401-bf4f-67e7b194694f",
      "name": "New Support Task",
      "is_default": false
    }
  ]
}

Aside from this API endpoint, templates are regular pages in Notion, so you can also get the template ID by opening the template, copying the URL, and extracting the ID from it. For example, if the template looks like https://notion.so/notion/New-Hire-Onboarding-a07589e357414b3285a8d02beb8fd9dd, the template id is a07589e357414b3285a8d02beb8fd9dd. Determining the ID of a template will be useful in the next step, where we'll create pages using templates.

Step 2: Create page using a template

By default, adding pages to a data source creates them with only the block children you provide. In other words, the content has to be built up from scratch manually.

In the Create a page API, this corresponds to the template[type] = "none" parameter. The two other options for type allow you to start taking advantage of the power of templates at page creation time:

template[type]template[template_id]Behavior
none (or omitted)N/ANo template. Provided children and properties are immediately applied.
defaultN/AApplies the data source's default template to the newly created page. children cannot be specified in the create page request.
template_id(ID of a template)Use an ID from the response of List data source templates, or copied from a URL, as the template_id. Indicates which exact template to apply to the newly created page. children cannot be specified in the create page request.

When using a template — either the default template or a specific template_id — the Create Page API request returns immediately with a Page object representing a blank page, aside from any initial properties (for example, the title) set on it. Store the ID of this page in your backend systems if you need it for Step 3 below.

Afterwards, Notion's systems quickly begin applying the chosen template in the background, replacing the page content and merging in the template's properties. Any placeholder values (e.g. "Current time when duplicating template"), are appropriately populated, the same way they would be when a Notion user applies a template in the app. The key difference is that the API bot user (rather than a person) is set as the "created by" user (i.e. author) of the new page.

📘

Check page and database permissions

The Notion API returns an HTTP 400 validation_error response in the following scenarios:

  • The provided template ID is invalid. Template IDs are UUIDs (v4) and look like page IDs in Notion.
  • The integration doesn't have access to the template. Generally, if a bot is connected to the data source's parent database, those permissions apply to all templates for the data source by default, since templates are represented as (special) pages under the data source.
    • However, to confirm, check the "Connections" list under the 3-dot overflow menu for a template to ensure your bot appears in the list.
  • Attempting to apply the default template when there isn't one. When using template[type]=default, ensure the parent in the Create Page request is pointing to the correct data_source_id, and that the data source has a template that's marked as "default".

Step 3: Confirm page contents are ready

After Step 2, Notion's systems asynchronously begin processing a task to populate the page contents and properties based on the template you identified. In most cases, this is visually very prompt when viewing the data source in the Notion app, but for API integrations, you might need an additional step to wait for processing to complete, in cases where your integration needs to take action once the page is ready.

Webhook setup

Go through the Webhooks guide to set up a webhook URL for your integration, and make sure you're using the newest API version in your webhook settings. Also, make sure you have enabled page.created and page.content_updated events.

How aggregated events work

Internally, Notion produces a page.content_updated event once the template duplication is complete, but in the API, such events might be aggregated into the base page.created event if they take place in a short enough time window, which will generally be the case. As a result, you might not see the page.created event immediately after Step 2 (the Create a page call). In these cases, the page.created event will be deferred until the page is ready.

In rare cases, or for complex templates, Notion's processing of the page might take longer. In this case, your integration may receive the page.created event for the blank page created from Step 2, and subsequently, a page.content_updated event when the page is ready.

For more information on event aggregation, refer to the detailed event types reference .

Webhook implementation

Putting the above flow together, your webhook handler can implement logic as follows:

  • When receiving a page.created or page.content_updated event with the entity ID matching the page Id created in Step 2 👀:
    • If the event is page.content_updated, you know the template has finished applying, and can proceed to any further steps your integration needs to take ✅.
    • If the event is page.created, call the Retrieve block children API using the page ID to check if the page content is a blank array, or if it includes the content you expect from the template 👀.
      • If the page contents have been populated, you know the template has finished applying, and can proceed to any further steps your integration needs to take ✅,
      • Otherwise, stop processing and wait for a page.content_updated event signaling the completion of applying the template ⏳.