### Clone and Install Dependencies Source: https://developers.notion.com/guides/get-started/quick-start Clone the Notion cookbook repository and install necessary Node.js dependencies for the web form with Express example. This includes Express.js, dotenv, and Notion's SDK for JavaScript. ```bash # Clone this repository locally git clone https://github.com/makenotion/notion-cookbook.git # Switch into this project cd notion-cookbook/examples/javascript/web-form-with-express/ # Install the dependencies npm install ``` -------------------------------- ### Install Node.js Packages Source: https://developers.notion.com/guides/tutorials/log-strava-activity-in-notion Command to install the necessary Node.js packages for the integration. ```shell npm install @notionhq/client dotenv express https ``` -------------------------------- ### Complete Page Example Source: https://developers.notion.com/guides/data-apis/enhanced-markdown A comprehensive example demonstrating headings, callouts, lists, code blocks, and mentions. ```markdown # Project kickoff {color="blue"} Ship the MVP by **Friday**. - [x] Write spec - [ ] Build prototype - [ ] Collect feedback ```python def greet(name): return f"Hello, {name}!" ``` | Status | Owner | |---|---| | In progress | Ada | ``` -------------------------------- ### Example response for GET /v1/users/me Source: https://developers.notion.com/guides/resources/historical-changelog This JSON response shows the structure of user information returned by the /v1/users/me endpoint. ```json { "object": "user", "id": "16d84278-ab0e-484c-9bdd-b35da3bd8905", "name": "pied piper", "avatar_url": null, "type": "bot", "bot": { "owner": { "type": "user", "user": { "object": "user", "id": "5389a034-eb5c-47b5-8a9e-f79c99ef166c", "name": "christine makenotion", "avatar_url": null, "type": "person", "person": { "email": "christine@makenotion.com" } } } } } ``` -------------------------------- ### Install MCP SDK and OAuth Libraries (npm) Source: https://developers.notion.com/guides/mcp/build-mcp-client Install the necessary libraries for building an MCP client in TypeScript/JavaScript using npm. ```bash npm install @modelcontextprotocol/sdk npm install oauth # or openid-client ``` ```bash npm install --save-dev @types/node ``` -------------------------------- ### Project Structure Example Source: https://developers.notion.com/guides/tutorials/log-strava-activity-in-notion Suggested project directory structure for organizing the integration code. ```shell project-root/ ├── src/ │ ├── config/ │ │ └── spotify.js │ │ └── notion.js │ ├── integrations/ │ │ ├── spotifyIntegration.js │ │ └── notionIntegration.js │ ├── main.js │ ├── server.js ``` -------------------------------- ### Install Required Node.js Packages Source: https://developers.notion.com/guides/tutorials/integrate-mailchimp-campaigns-with-notion-databases Command to install the Notion client and dotenv package for environment variable management. ```shell npm install @notionhq/client dotenv ``` -------------------------------- ### Start the OAuth Server Source: https://developers.notion.com/guides/tutorials/log-strava-activity-in-notion Run this command in your terminal to start the local server for the OAuth flow with Strava. ```shell node src/server.js ``` -------------------------------- ### Run the Connection Script Source: https://developers.notion.com/guides/tutorials/integrate-mailchimp-campaigns-with-notion-databases Execute the main script to start the integration process. This command assumes your project is set up with npm. ```shell npm start ``` -------------------------------- ### JSON Expandable Theme Example Source: https://developers.notion.com/guides/resources/historical-changelog Example of a JSON structure for an expandable theme, used for UI elements. ```json { "children": [ { "object": "block", "type": "column", "column": { "children": [ { "object": "block", "type": "paragraph", "paragraph": { "text": [ { "type": "text", "text": { "content": "some text here" } } ] } } ] } } ] } ``` -------------------------------- ### Position a New Database View at the Start Source: https://developers.notion.com/guides/data-apis/working-with-views Use the 'start' type within the 'position' parameter to ensure a new top-level database view appears as the first tab in the view tab bar. This parameter is only valid when creating a top-level database view. ```json { "position": { "type": "start" } } ``` -------------------------------- ### Create Board View Source: https://developers.notion.com/guides/data-apis/working-with-views This example demonstrates how to create a Board view with specific configurations for grouping, cover images, and card layout. ```APIDOC ## POST /v1/views ### Description Creates a new view for a database or adds a widget to a dashboard. ### Method POST ### Endpoint https://api.notion.com/v1/views ### Parameters #### Query Parameters - **database_id** (string) - Optional - The ID of the database to create the view in. Mutually exclusive with `view_id` and `create_database`. - **view_id** (string) - Optional - The ID of a dashboard view to add this view to as a widget. Mutually exclusive with `database_id` and `create_database`. - **create_database** (object) - Optional - Creates a linked database view on a page referencing an existing data source. Mutually exclusive with `database_id` and `view_id`. - **filter** (object) - Optional - A filter object to apply. Uses the same shape as data source queries. - **sorts** (array) - Optional - An array of sort objects. Uses the same shape as data source queries. - **quick_filters** (object) - Optional - A map of quick filters for the view's filter bar. Keys are property names or IDs, values are filter conditions. - **configuration** (object) - Optional - A view configuration object. The `type` field inside must match the view `type`. - **position** (object) - Optional - Where to place the new view in the database's view tab bar. Only applicable when `database_id` is provided. Defaults to appending at the end. - **placement** (object) - Optional - Where to place the new widget in a dashboard layout. Only applicable when `view_id` is provided. Defaults to creating a new row at the end. ### Request Body - **database_id** (string) - Required if not using `view_id` or `create_database`. - **data_source_id** (string) - Required when creating a linked database view. - **name** (string) - Required - The name of the view. - **type** (string) - Required - The type of the view (e.g., 'board', 'table', 'list', 'calendar', 'gallery', 'timeseries'). - **configuration** (object) - Required - The configuration for the view, specific to its type. - **type** (string) - Required - Must match the view `type`. - **group_by** (object) - Optional - Configuration for grouping the view. - **cover** (object) - Optional - Configuration for the view's cover. - **cover_size** (string) - Optional - The size of the cover images. - **card_layout** (string) - Optional - The layout of cards in the view. ### Request Example ```json { "database_id": "DATABASE_ID", "data_source_id": "DATA_SOURCE_ID", "name": "Task board", "type": "board", "configuration": { "type": "board", "group_by": { "type": "status", "property_id": "STATUS_PROPERTY_ID", "group_by": "group", "sort": { "type": "manual" } }, "cover": { "type": "page_cover" }, "cover_size": "medium", "card_layout": "compact" } } ``` ### Response #### Success Response (200) - **object** (object) - The created view object. #### Response Example ```json { "object": "view", "id": "VIEW_ID", "type": "board", "created_time": "2023-01-01T12:00:00Z", "last_edited_time": "2023-01-01T12:00:00Z", "parent": { "type": "database_id", "database_id": "DATABASE_ID" }, "url": "https://www.notion.so/VIEW_ID", "properties": {}, "view": { "id": "VIEW_ID", "type": "board", "board": { "group_by": { "type": "status", "property_id": "STATUS_PROPERTY_ID", "direction": "ascending" }, "visible_groups": [ { "value": "todo", "name": "To Do", "color": "default" } ], "cover": { "type": "page_cover" }, "cover_size": "medium", "card_wrap": false, "card_display_property": null, "card_layout": "compact" } } } ``` ``` -------------------------------- ### Run the Connection Script Source: https://developers.notion.com/guides/tutorials/log-strava-activity-in-notion Execute this command to start the main script that connects Strava activities to your Notion database. ```shell npm start ``` -------------------------------- ### Notion API Database Response Example Source: https://developers.notion.com/guides/get-started/quick-start Example JSON object returned by the /databases endpoint, containing database details. ```json { "message": "success!", "data": { "object": "database", "id": "e604f78c-4145-4444-b7d5-1adea4fa5d08", "cover": null, "icon": null, "created_time": "2023-07-18T20:56:00.000Z", "created_by": { "object": "user", "id": "44b170f0-16ac-47cf-aaaa-8f2eab66hhhh" }, "last_edited_by": { "object": "user", "id": "44b170f0-16ac-47cf-gggg-8f2eab6rrrra" }, "last_edited_time": "2023-07-18T20:56:00.000Z", "title": [ { "type": "text", "text": [Object], "annotations": [Object], "plain_text": "test db", "href": null } ], "description": [], "is_inline": false, "properties": { "Name": { "id": "title", "name": "Name", "type": "title", "title": {} } }, "parent": { "type": "page_id", "page_id": "e7261079-9d30-4313-9999-14b29880gggg" }, "url": "", "public_url": null, "archived": false, "in_trash": false } } ``` -------------------------------- ### File Object Example (JSON) Source: https://developers.notion.com/guides/data-apis/retrieving-files This is an example of a file object returned when retrieving block children. The `url` is a temporary signed link that expires after 1 hour. Re-fetch the page to refresh it. ```json { "type": "file", "file": { "url": "https://s3.us-west-2.amazonaws.com/secure.notion-static.com/", "expiry_time": "2025-04-24T22:49:22.765Z" } } ``` -------------------------------- ### Example User API Object Response Source: https://developers.notion.com/guides/data-apis/working-with-files-and-media Illustrates an example API response for a bot user in a free workspace, showing a max file upload size of 5 MiB (5242880 bytes). This helps in understanding the practical values returned. ```json { "object": "user", "id": "be51669b-1932-4a11-8d35-38fbc2e1e4fd", "type": "bot", "bot": { "owner": { "type": "workspace" }, "workspace_name": "Cat's Notion", "workspace_limits": { "max_file_upload_size_in_bytes": 5242880 } } } ``` -------------------------------- ### Basic Express Server Setup with Notion SDK Initialization Source: https://developers.notion.com/guides/get-started/quick-start This Node.js code sets up a basic Express server that serves static files and handles requests to the root URL by sending index.html. It also initializes the Notion SDK client using an API key from environment variables, preparing for Notion API interactions. ```javascript require("dotenv").config(); const express = require("express"); const app = express(); // Notion SDK for JavaScript const { Client } = require("@notionhq/client"); const notion = new Client({ auth: process.env.NOTION_KEY }); // app.use(express.static("public")); // app.get("/", function(request, response) { response.sendFile(__dirname + "/views/index.html"); }); // listen for requests const listener = app.listen(process.env.PORT, function() { console.log("Your app is listening on port " + listener.address().port); }); ``` -------------------------------- ### Retrieve File Page Property Source: https://developers.notion.com/guides/resources/historical-changelog When retrieving file page properties, you will now get a link to the file as well as its name. This example shows the structure of a file property with both internal and external file types. ```json { "object": "page", "properties": { "Files": { "id": "YP~`", "type": "files", "files": [ { "name": "Brocolli", "type": "file", "file": { "url": "https://s3.us-west-2.amazonaws.com/secure.notion-static.com/c32db351-d1ea-40c2-9660-820db28c44ad/brocolli.jpeg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAT73L2G45O3KS52Y5%2F20210820%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20210820T211042Z&X-Amz-Expires=3600&X-Amz-Signature=859a24c9b7153860b252fa5955829a97632650dcdc5e91c7a831a48c5efecae4&X-Amz-SignedHeaders=host", "expiry_time": "2021-08-20T22:10:42.022Z" } }, { "name": "Text File", "type": "external", "external": { "url": "https://website.domain/files/doc.txt" } } ] } }, "// ... remaining properties" } ``` -------------------------------- ### Initialize Notion API Client Source: https://developers.notion.com/guides/tutorials/log-strava-activity-in-notion Sets up the Notion API client using the official SDK. Requires Notion integration token and database ID from environment variables. ```javascript // notion.js const { Client } = require('@notionhq/client'); const dotenv = require('dotenv'); dotenv.config(); const notion = new Client({ auth: process.env.NOTION_TOKEN }); const databaseId = process.env.NOTION_DATABASE_ID; module.exports = { notion, databaseId }; ``` -------------------------------- ### List and Create Pages with Templates Source: https://developers.notion.com/guides/get-started/preparing-for-users These examples demonstrate how to list available templates for a data source and how to create a new page using a default template. ```APIDOC ## List available templates for the data source ### Method GET ### Endpoint /v1/data_sources/DATA_SOURCE_ID/templates ### Request Example 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 ### Method POST ### Endpoint /v1/pages ### Request Body - **parent** (object) - Required - The parent of the page. - **type** (string) - Required - Must be "data_source_id". - **data_source_id** (string) - Required - The ID of the data source. - **properties** (object) - Required - The properties of the page. - **Task** (object) - Required - Example property for the page title. - **title** (array) - Required - An array of rich text objects. - **type** (string) - Required - Must be "text". - **text** (object) - Required - The text content. - **content** (string) - Required - The text content of the page title. - **template** (object) - Required - Specifies the template to use. - **type** (string) - Required - Must be "default". ### Request Example ```json { "parent": { "type": "data_source_id", "data_source_id": "DATA_SOURCE_ID" }, "properties": { "Task": { "title": [{"type": "text", "text": {"content": "My first task"}}] } }, "template": { "type": "default" } } ``` ### Response Example (Success Response - 200) ```json { "object": "page", "id": "PAGE_ID", "created_time": "2021-05-17T19:01:00.000Z", "last_edited_time": "2021-05-17T19:01:00.000Z", "parent": { "type": "data_source_id", "data_source_id": "DATA_SOURCE_ID" }, "properties": { "Task": { "title": [{"type": "text", "text": {"content": "My first task"}}] } } } ``` ``` ```APIDOC // List available templates for the data source const templates = await notion.dataSources.listTemplates({ data_source_id: dataSourceId, }); // Create a page using the default template const page = await notion.pages.create({ parent: { type: "data_source_id", data_source_id: dataSourceId, }, properties: { Task: { title: [{ type: "text", text: { content: "My first task" } }], }, }, template: { type: "default", }, }); ``` -------------------------------- ### Fetch data source ID using JS SDK Source: https://developers.notion.com/guides/get-started/upgrade-guide-2025-09-03 This JavaScript SDK example demonstrates how to call the Get Database API and extract the `data_sources` array. Ensure your `Notion-Version` is set to `2025-09-03` for this call. ```typescript let notion = new Client({ auth: "{ACCESS_TOKEN}", notionVersion: "2025-09-03", }) const DATABASE_ID = "/* ... */" try { const response = await notion.request({ method: "get", path: `databases/${DATABASE_ID}`, }) const dataSources = response.data_sources // [{ id: "...", name: "..." }, ...] console.log(dataSources) // In the existing, single-source database case, there will only // be one data source. const dataSource = dataSources[0] } catch (error) { // Handle `APIResponseError` console.error(error) } // ... Remaining code, not migrated yet. notion = new Client({ auth: "{ACCESS_TOKEN}", notionVersion: "2022-06-28", }) // ... ``` -------------------------------- ### Callout Block Example Source: https://developers.notion.com/guides/resources/historical-changelog Example of a callout block structure in JSON format. Used for highlighting important notes. ```json { "object": "block", "id": "block-id", "created_time": "2021-10-07T19:23:00.000Z", "last_edited_time": "2021-10-07T19:24:00.000Z", "has_children": false, "archived": false, "type": "callout", "callout": { "text": [ { "type": "text", "text": { "content": "Note: Something special is happening above", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "Note: Something special is happening above", "href": null } ], "icon": { "type": "emoji", "emoji": "💡" } } } ``` -------------------------------- ### Create a Dashboard View Source: https://developers.notion.com/guides/data-apis/working-with-views Use this endpoint to create a new dashboard view. Pass `type: "dashboard"` with a `database_id` to initiate the creation. ```bash curl -X POST https://api.notion.com/v1/views \ -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \ -H "Content-Type: application/json" \ -H "Notion-Version: 2025-09-03" \ --data '{ \ "database_id": "DATABASE_ID", \ "data_source_id": "DATA_SOURCE_ID", \ "name": "Project overview", \ "type": "dashboard" \ }' ``` -------------------------------- ### Start a file upload Source: https://developers.notion.com/guides/data-apis/importing-external-files Initiate the process of transferring a temporarily-hosted public file into your Notion workspace using the file_uploads endpoint with a mode of "external_url". ```APIDOC ## POST /v1/file_uploads ### Description Initiates the transfer of a public file from an external URL into your Notion workspace. ### Method POST ### Endpoint /v1/file_uploads ### Parameters #### Request Body - **mode** (string) - Required - Must be set to "external_url". - **external_url** (string) - Required - The publicly accessible URL of the file. - **filename** (string) - Required - The desired name for the file in Notion. ### Request Example ```json { "mode": "external_url", "external_url": "https://example.com/image.png", "filename": "image.png" } ``` ### Response #### Success Response (200) - **id** (string) - The unique identifier for the file upload. - **object** (string) - The type of object, which is "file_upload". - **created_time** (string) - The timestamp when the file upload was created. - **last_edited_time** (string) - The timestamp when the file upload was last edited. - **url** (string) - The URL of the uploaded file in Notion. - **status** (string) - The current status of the file upload (e.g., "processing", "completed"). #### Error Handling - **validation_error** (HTTP 400) - Returned if: - The URL is not SSL-enabled or not publicly accessible. - The URL doesn't expose the `Content-Type` header. - The file size exceeds the workspace's per-file limit. - A valid filename and supported MIME content type or extension are not provided. ``` -------------------------------- ### Create a database with relation and rollup properties Source: https://developers.notion.com/guides/resources/historical-changelog Example of creating a new database with 'Name' as the title property, and adding 'relation' and 'rollup' property types. Ensure the related database is shared with the integration. ```bash curl --location --request POST 'https://api.notion.com/v1/databases/' \ --header 'Authorization: Bearer "$NOTION_API_KEY"' \ --header 'Content-Type: application/json' \ --header 'Notion-Version: 2021-08-16' \ --data '{ \ "parent": { \ "type": "page_id", \ "page_id": "98ad959b-2b6a-4774-80ee-00246fb0ea9b" \ }, \ "title": [ \ { \ "type": "text", \ "text": { \ "content": "Grocery List", \ "link": null \ } \ } \ ], \ "properties": { \ "Name": { \ "title": {} \ ``` -------------------------------- ### Group by Select Property Example Source: https://developers.notion.com/guides/data-apis/working-with-views Configure grouping for a select property. This example shows manual sorting and hiding empty groups. ```json { "type": "select", "property_id": "PRIORITY_PROPERTY_ID", "sort": { "type": "manual" }, "hide_empty_groups": true } ``` -------------------------------- ### Table Block Example Source: https://developers.notion.com/guides/resources/historical-changelog Example JSON structure for creating a table block. This block serves as a parent for table row children and contains formatting data. ```json { "type": "table", "table": { "table_width": 3, "has_column_header": false, "has_row_header": false } } ``` -------------------------------- ### Configure Notion MCP Server in VS Code (Workspace) Source: https://developers.notion.com/guides/mcp/get-started-with-mcp Create a `.vscode/mcp.json` file in your workspace to configure the Notion MCP server. Use the Command Palette to list and start servers. ```json { "servers": { "notion": { "type": "http", "url": "https://mcp.notion.com/mcp" } } } ``` -------------------------------- ### Retrieve bot user information with GET /v1/users/me Source: https://developers.notion.com/guides/resources/historical-changelog Use this endpoint to get details about the bot associated with your API token. Requires API version 2021-08-16 or later. ```bash curl --request GET \ --url http://localhost:3000/v1/users/me \ --header 'Authorization: Bearer $NOTION_API_KEY' \ --header 'Notion-Version: 2021-08-16' ``` -------------------------------- ### Example Notion Database JSON Source: https://developers.notion.com/guides/resources/historical-changelog This JSON represents an example Notion database structure, including various property types like formula, checkbox, rich text, and number. ```json { "object": "database", "id": "c23f0085-a061-41c0-b8a6-cbe14d15a4de", "created_time": "2021-08-20T16:08:00.000Z", "last_edited_time": "2021-08-20T16:08:00.000Z", "title": [ { "type": "text", "text": { "content": "Grocery List", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "Grocery List", "href": null } ], "properties": { "Cost of next trip": { "id": "Rbq\", "name": "Cost of next trip", "type": "formula", "formula": { "expression": "if(prop(\"In stock\"), 0, prop(\"Price\"))" } }, "In stock": { "id": "\JwC", "name": "In stock", "type": "checkbox", "checkbox": {} }, "Description": { "id": "`}HT", "name": "Description", "type": "rich_text", "rich_text": {} }, "Price": { "id": "u|<{", "name": "Price", "type": "number", "number": { "format": "dollar" } }, "Name": { "id": "title", "name": "Name", "type": "title", "title": {} } }, "parent": { "type": "page_id", "page_id": "98ad959b-2b6a-4774-80ee-00246fb0ea9b" } } ``` -------------------------------- ### Retrieve Block Children Example Source: https://developers.notion.com/guides/resources/historical-changelog Example response from the Retrieve block children endpoint, showing a child database uploaded to Notion. This response structure is typical for listing child blocks. ```json { "object": "list", "results": [ { "object": "block", "id": "0d6ff4f9-1211-4129-ab4a-19dfc33d4d7a", "created_time": "2021-09-27T20:25:00.000Z", "last_edited_time": "2021-09-27T20:25:00.000Z", "has_children": false, "archived": false, "type": "child_database", "child_database": { "title": "My child database" } } ], "next_cursor": null, "has_more": false } ``` -------------------------------- ### Table Row Block Example Source: https://developers.notion.com/guides/resources/historical-changelog Example JSON structure for a table row block, which is a child of a table block. It includes an array of cells, where each cell contains rich text content. ```json { "type": "table_row", "table_row": { "cells": [ [ { "type": "text", "text": { "content": "column 1 content", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "column 1 content", "href": null } ], [ { "type": "text", "text": { ``` -------------------------------- ### Configure Environment Variables Source: https://developers.notion.com/guides/get-started/quick-start Add your Notion API key and parent page ID to your .env file. Ensure you add .env to your .gitignore to prevent accidental sharing. ```bash NOTION_KEY= NOTION_PAGE_ID= ``` -------------------------------- ### Simple Rich Text Object Example Source: https://developers.notion.com/guides/data-apis/working-with-page-content This example shows a basic rich text object representing the string 'Grocery List'. It includes type, text content, and annotation details. ```JavaScript { "type": "text", "text": { "content": "Grocery List", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "Grocery List", "href": null } ``` -------------------------------- ### Create Database with Formula Property Source: https://developers.notion.com/guides/resources/historical-changelog Example request to create a new database that includes a 'formula' property type. Requires API key and specific version. ```bash curl --location --request POST 'https://api.notion.com/v1/databases/' \ --header 'Authorization: Bearer "$NOTION_API_KEY"' \ --header 'Content-Type: application/json' \ --header 'Notion-Version: 2021-05-13' \ --data '{ \ "parent": { \ "type": "page_id", \ "page_id": "98ad959b-2b6a-4774-80ee-00246fb0ea9b" \ }, \ "title": [ \ { \ "type": "text", \ "text": { \ "content": "Grocery List", \ "link": null \ } \ } \ ], \ "properties": { \ "Name": { \ "title": {} \ }, \ "Description": { \ "rich_text": {} \ }, \ "In stock": { \ "checkbox": {} \ }, \ "Price": { \ "number": { \ "format": "dollar" \ } \ }, \ "Cost of next trip": { \ "formula": { \ ``` -------------------------------- ### Create Database with Default View (cURL) Source: https://developers.notion.com/guides/data-apis/working-with-views Use this cURL command to create a new database. Notion automatically provisions a data source and a default table view for it. ```bash 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 '{ \ "parent": { "type": "page_id", "page_id": "YOUR_PAGE_ID" }, \ "title": [{ "type": "text", "text": { "content": "My Database" } }], \ "is_inline": false \ }' ``` -------------------------------- ### Array Rollup Property Example Source: https://developers.notion.com/guides/resources/historical-changelog This example demonstrates the structure of an array rollup property for rich text values, as returned by the API version 2021-08-16. Note the consistent 'rich_text' type for elements within the array. ```json { "properties": { "sample text array rollup": { "id": "NXTh", "type": "rollup", "rollup": { "type": "array", "array": [ { "type": "rich_text", "rich_text": [ { "type": "text", "text": { "content": "Sample text", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "Sample text", "href": null } ] } ] } } } } ``` -------------------------------- ### Fetch data source ID using Get Database API Source: https://developers.notion.com/guides/get-started/upgrade-guide-2025-09-03 Use the `GET /v1/databases/:database_id` endpoint with the `2025-09-03` Notion-Version header to retrieve child data sources. This is crucial for identifying and migrating database IDs. ```json // GET /v1/databases/{database_id} // Notion-Version: "2025-09-03" // --- // RETURNS --> { "object": "database", "id": "{database_id}", "title": [/* ... */], "parent": { "type": "page_id", "page_id": "255104cd-477e-808c-b279-d39ab803a7d2" }, "is_inline": false, "in_trash": false, "created_time": "2025-08-07T10:11:07.504-07:00", "last_edited_time": "2025-08-10T15:53:11.386-07:00", "data_sources": [ { "id": "{data_source_id}", "name": "My Task Tracker" } ], "icon": null, "cover": null, // ... } ``` -------------------------------- ### Complete MCP Client Example Source: https://developers.notion.com/guides/mcp/build-mcp-client This class encapsulates the entire process of initializing, authenticating, and connecting to the MCP service. It handles OAuth metadata discovery, client registration, authorization flow, token exchange, and client creation with fallback to SSE transport if Streamable HTTP fails. Ensure secure storage and retrieval mechanisms are implemented for sensitive data like code verifiers and state parameters. ```typescript import { Client } from "@modelcontextprotocol/sdk/client/index.js" import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js" import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js" import { randomBytes, createHash } from "crypto" class NotionMcpClient { private serverUrl = "https://mcp.notion.com" private metadata!: OAuthMetadata private clientId!: string private clientSecret?: string private accessToken?: string private refreshToken?: string private client?: Client async initialize(redirectUri: string): Promise { this.metadata = await discoverOAuthMetadata(this.serverUrl) const credentials = await registerClient(this.metadata, redirectUri) this.clientId = credentials.client_id this.clientSecret = credentials.client_secret } async startAuthFlow(redirectUri: string): Promise { const codeVerifier = generateCodeVerifier() const codeChallenge = generateCodeChallenge(codeVerifier) const state = generateState() // Store these securely this.storeSecurely("codeVerifier", codeVerifier) this.storeSecurely("state", state) return buildAuthorizationUrl( this.metadata, this.clientId, redirectUri, codeChallenge, state ) } async handleCallback( callbackUrl: string, redirectUri: string ): Promise { const storedState = this.retrieveSecurely("state") const codeVerifier = this.retrieveSecurely("codeVerifier") const code = await handleCallback( callbackUrl, storedState, codeVerifier ) const tokens = await exchangeCodeForTokens( code, codeVerifier, this.metadata, this.clientId, this.clientSecret, redirectUri ) this.accessToken = tokens.access_token this.refreshToken = tokens.refresh_token // Clean up stored values this.deleteSecurely("state") this.deleteSecurely("codeVerifier") } async connect(): Promise { if (!this.accessToken) { throw new Error("Not authenticated") } try { this.client = await createMcpClient( this.serverUrl, this.accessToken, false ) } catch (error) { console.warn("Streamable HTTP failed, falling back to SSE") this.client = await createMcpClient( this.serverUrl, this.accessToken, true ) } return this.client } async ensureValidToken(): Promise { if (!this.refreshToken) { throw new Error("No refresh token available") } try { const tokens = await refreshAccessToken( this.refreshToken, this.metadata, this.clientId, this.clientSecret ) this.accessToken = tokens.access_token if (tokens.refresh_token) { this.refreshToken = tokens.refresh_token } } catch (error) { if ( error instanceof Error && error.message === "REAUTH_REQUIRED" ) { throw new Error("Re-authentication required") } throw error } } private storeSecurely(key: string, value: string): void { // Implement secure storage } private retrieveSecurely(key: string): string { // Implement secure retrieval return "" } private deleteSecurely(key: string): void { // Implement secure deletion } } ``` -------------------------------- ### Create a Table View with Filters and Sorts Source: https://developers.notion.com/guides/data-apis/working-with-views Use this endpoint to create a new table view for a database. Specify the data source, name, type, and optionally include filters, sorts, and configuration. ```bash 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": "Recent orders", \ "type": "table", \ "filter": { \ "property": "Last ordered", \ "date": { \ "past_week": {} \ } \ }, \ "sorts": [ \ { \ "property": "Last ordered", \ "direction": "descending" \ } \ ], \ "configuration": { \ "type": "table", \ "properties": [ \ { "property_id": "title", "visible": true, "width": 300 }, \ { "property_id": "abc1", "visible": true, "width": 200 } \ ], \ "wrap_cells": true \ } \ }' ``` ```javascript const view = await notion.views.create({ database_id: "DATABASE_ID", data_source_id: "DATA_SOURCE_ID", name: "Recent orders", type: "table", filter: { property: "Last ordered", date: { past_week: {}, }, }, sorts: [ { property: "Last ordered", direction: "descending", }, ], configuration: { type: "table", properties: [ { property_id: "title", visible: true, width: 300 }, { property_id: "abc1", visible: true, width: 200 }, ], wrap_cells: true, }, }); console.log(view.id); // The new view's ID console.log(view.url); // Deep link to the view in Notion ``` -------------------------------- ### Parse Text from Any Block Type (JavaScript Example) Source: https://developers.notion.com/guides/resources/historical-changelog An example from the Notion SDK for JavaScript demonstrating how to extract plain text from various block types supported by the public API. This is useful for processing content within Notion pages. ```javascript const block = { // ... block object properties ... }; function getPlainText(block) { switch (block.type) { case 'paragraph': case 'heading_1': case 'heading_2': case 'heading_3': case 'bulleted_list_item': case 'numbered_list_item': case 'to_do': case 'toggle': case 'quote': case 'callout': return block.text?.map(t => t.plain_text).join('') || ''; case 'code': return block.code?.caption?.map(t => t.plain_text).join('') || ''; // Add other block types as needed default: return ''; } } ``` -------------------------------- ### Create a Board View Source: https://developers.notion.com/guides/data-apis/working-with-views Use this to create a board view with specific configurations for grouping, cover images, and card layout. Ensure you provide the correct database ID, data source ID, and property IDs. ```bash 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", "configuration": { "type": "board", "group_by": { "type": "status", "property_id": "STATUS_PROPERTY_ID", "group_by": "group", "sort": { "type": "manual" } }, "cover": { "type": "page_cover" }, "cover_size": "medium", "card_layout": "compact" } }' ``` ```javascript const boardView = await notion.views.create({ database_id: "DATABASE_ID", data_source_id: "DATA_SOURCE_ID", name: "Task board", type: "board", configuration: { type: "board", group_by: { type: "status", property_id: "STATUS_PROPERTY_ID", group_by: "group", sort: { type: "manual" }, }, cover: { type: "page_cover", }, cover_size: "medium", card_layout: "compact", }, }); ``` -------------------------------- ### List and Create Pages with Templates using JavaScript Source: https://developers.notion.com/guides/get-started/preparing-for-users Use the Notion SDK for JavaScript to list available templates for a data source and create a new page using the default template. Ensure the dataSourceId is correctly configured. ```javascript // List available templates for the data source const templates = await notion.dataSources.listTemplates({ data_source_id: dataSourceId, }); // Create a page using the default template const page = await notion.pages.create({ parent: { type: "data_source_id", data_source_id: dataSourceId, }, properties: { Task: { title: [{ type: "text", text: { content: "My first task" } }], }, }, template: { type: "default", }, }); ```