Skip to main content
Most public integrations need specific databases, pages, or views to work. Traditionally, that meant waiting for the user to share pages manually or duplicate a static template during OAuth — both add friction and delay how quickly your integration delivers value. With the Notion API, public integrations can skip those steps entirely. Right after a user authorizes your integration, you can create the exact databases, pages, and views your integration needs — no extra user action required. In this guide, you’ll learn how to:
  • Create databases and pages directly in a user’s workspace
  • Configure views with filters, sorts, and layout types
  • Populate pages using database templates

How it works

1

User authorizes your integration

The user goes through the standard OAuth flow. You receive an access_token with the capabilities your integration requested. No template URL is needed.
2

Create databases and pages

Use the API to create databases and pages at the workspace level. These appear in the user’s Private section in Notion.
3

Configure views

Use the views API to add views (table, board, calendar, etc.) to your newly created databases, with the filters and sorts your integration needs.
4

Optionally apply templates

If your databases have data source templates, you can create pages that start from those templates for a richer initial experience.

Creating workspace-level content

Public integrations can create pages and databases at the workspace level by omitting the parent parameter (or setting it to { "type": "workspace", "workspace": true }). This places the content in the authorizing user’s Private section.
This capability is only available to public integrations. Internal integrations cannot create workspace-level content because they aren’t owned by a single user.

Create a database

curl -X POST https://api.notion.com/v1/databases \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2026-03-11" \
  --data '{
    "title": [{ "type": "text", "text": { "content": "Project Tracker" } }],
    "is_inline": false,
    "initial_data_source": {
      "properties": {
        "Task": { "title": {} },
        "Status": {
          "status": {
            "options": [
              { "name": "Not started", "color": "default" },
              { "name": "In progress", "color": "blue" },
              { "name": "Done", "color": "green" }
            ]
          }
        },
        "Assignee": { "people": {} },
        "Due date": { "date": {} }
      }
    }
  }'
The new database is created with one data source and one default Table view. Store the database.id and database.data_sources[0].id — you’ll need them to create views and pages.

Create a standalone page

curl -X POST https://api.notion.com/v1/pages \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2026-03-11" \
  --data '{
    "properties": {
      "title": {
        "title": [{ "type": "text", "text": { "content": "Getting Started" } }]
      }
    },
    "children": [
      {
        "object": "block",
        "type": "heading_2",
        "heading_2": {
          "rich_text": [{ "type": "text", "text": { "content": "Welcome!" } }]
        }
      },
      {
        "object": "block",
        "type": "paragraph",
        "paragraph": {
          "rich_text": [
            { "type": "text", "text": { "content": "This page was created by your integration. You can move it anywhere in your workspace." } }
          ]
        }
      }
    ]
  }'

Adding views

After creating a database, you can add views that match your integration’s use cases. Each database starts with a default Table view, but you’ll likely want to create additional views with specific filters, sorts, and layout types. For a project tracker, you might want a Board view grouped by status and a Calendar view for due dates:
# Board view: tasks grouped by status
curl -X POST https://api.notion.com/v1/views \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2026-03-11" \
  --data '{
    "database_id": "DATABASE_ID",
    "data_source_id": "DATA_SOURCE_ID",
    "name": "Task board",
    "type": "board"
  }'

# Calendar view: tasks by due date
curl -X POST https://api.notion.com/v1/views \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2026-03-11" \
  --data '{
    "database_id": "DATABASE_ID",
    "data_source_id": "DATA_SOURCE_ID",
    "name": "Schedule",
    "type": "calendar"
  }'

# Filtered table: only active tasks
curl -X POST https://api.notion.com/v1/views \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2026-03-11" \
  --data '{
    "database_id": "DATABASE_ID",
    "data_source_id": "DATA_SOURCE_ID",
    "name": "Active tasks",
    "type": "table",
    "filter": {
      "property": "Status",
      "status": {
        "does_not_equal": "Done"
      }
    },
    "sorts": [
      {
        "property": "Due date",
        "direction": "ascending"
      }
    ]
  }'
See the Working with views guide for full details on creating, updating, and querying views.

Applying templates

If your integration pre-configures database templates for the data source, you can create pages that start from those templates. This is useful for providing users with structured starting points — for example, a “Bug report” template with pre-filled sections.
# List available templates for the data source
curl -X GET "https://api.notion.com/v1/data_sources/DATA_SOURCE_ID/templates" \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Notion-Version: 2026-03-11"

# Create a page using the default template
curl -X POST https://api.notion.com/v1/pages \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H "Content-Type: application/json" \
  -H "Notion-Version: 2026-03-11" \
  --data '{
    "parent": {
      "type": "data_source_id",
      "data_source_id": "DATA_SOURCE_ID"
    },
    "properties": {
      "Task": {
        "title": [{ "type": "text", "text": { "content": "My first task" } }]
      }
    },
    "template": {
      "type": "default"
    }
  }'
Template content is applied asynchronously after the page is created. If your integration needs to take action once the template is fully applied, use webhooks to listen for page.content_updated events. See the Creating pages from templates guide for the full workflow.

Programmatic setup vs. template duplication

Template URL (OAuth)Programmatic setup
CustomizationStatic — every user gets the same templateDynamic — tailor content to each user
Schema controlSnapshot; changes require updating the source pageFull control over properties and views at creation time
Multiple databasesOne template page per integrationCreate as many databases and pages as needed
View configurationViews duplicated as-isCreate views with specific filters, sorts, and types
User interactionUser must choose “Duplicate template” during OAuthNo extra steps — setup happens after authorization
Template duplication still works well for simple integrations where a single static page is enough. Use programmatic setup when you need multiple resources, per-user customization, or want to keep the workspace in sync with an external system.
What’s next Now that you know how to set up workspace content, explore the APIs used in this guide: