### 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",
},
});
```