notion
Notion API for creating and managing pages, databases, and blocks. Use when user asks to "take notes", "create in Notion", "update Notion page", "query database", or needs to organize information in N
SKILL.mdskills/notion/SKILL.md
GitHubnotion
Use the Notion API to create/read/update pages, data sources (databases), and blocks.
Setup
- Create an integration at https://notion.so/my-integrations
- Copy the API key (starts with
ntn_orsecret_) - Store it:
mkdir -p ~/.config/notion
echo "ntn_your_key_here" > ~/.config/notion/api_key
- Share target pages/databases with your integration (click "..." → "Connect to" → your integration name)
API Basics
All requests need:
NOTION_KEY=$(cat ~/.config/notion/api_key)
curl -X GET "https://api.notion.com/v1/..." \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json"
Note: The
Notion-Versionheader is required. This skill uses2025-09-03(latest). In this version, databases are called "data sources" in many API responses and query flows.
Common Operations
Search for pages and data sources:
curl -X POST "https://api.notion.com/v1/search" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"query": "page title"}'
Get page:
curl "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03"
Get page content (blocks):
curl "https://api.notion.com/v1/blocks/{page_id}/children" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03"
Create a database:
curl -X POST "https://api.notion.com/v1/databases" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"parent": {"type": "page_id", "page_id": "PARENT_PAGE_ID"},
"title": [{"text": {"content": "My Database"}}],
"initial_data_source": {
"properties": {
"Name": {"title": {}},
"Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}}
}
}
}'
The response is a database object that includes a data_sources array. Use the returned data_sources[0].id value as the data_source_id when creating pages or querying the database contents. If the response is partial and data_sources is missing, retrieve the full object with GET /v1/databases/{database_id} to find the data_source_id.
Create page in a data source:
To add items to a database, target its data_source_id, not its database_id.
curl -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"parent": {"type": "data_source_id", "data_source_id": "DATA_SOURCE_ID"},
"properties": {
"Name": {"title": [{"text": {"content": "New Item"}}]},
"Status": {"select": {"name": "Todo"}}
}
}'
Query a data source (database):
curl -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"filter": {"property": "Status", "select": {"equals": "Active"}},
"sorts": [{"property": "Date", "direction": "descending"}]
}'
Update page properties:
curl -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"properties": {"Status": {"select": {"name": "Done"}}}}'
Add blocks to page:
curl -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"children": [
{"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "Hello"}}]}}
]
}'
Property Types
Common property formats for database items:
- Title:
{"title": [{"text": {"content": "..."}}]} - Rich text:
{"rich_text": [{"text": {"content": "..."}}]} - Select:
{"select": {"name": "Option"}} - Multi-select:
{"multi_select": [{"name": "A"}, {"name": "B"}]} - Date:
{"date": {"start": "2024-01-15", "end": "2024-01-16"}} - Checkbox:
{"checkbox": true} - Number:
{"number": 42} - URL:
{"url": "https://..."} - Email:
{"email": "a@b.com"} - Relation:
{"relation": [{"id": "page_id"}]}
Key Differences in 2025-09-03
- Databases → Data Sources: Use
/data_sources/endpoints for queries and retrieval. - Database creation: Use
POST /v1/databaseswithinitial_data_sourceto define the first schema. - Two IDs: Each database now has both a
database_idand adata_source_id.- Use
data_source_idwhen creating pages (parent: {"type": "data_source_id", "data_source_id": "..."}) and when querying (POST /v1/data_sources/{id}/query). - The
database_idis still accepted for backward compatibility in page parents, butdata_source_idis the canonical approach in 2025-09-03.
- Use
- Finding the data_source_id: Call
GET /v1/databases/{database_id}— the response includes adata_sourcesarray with each child'sidandname. Alternatively, search results return databases with theirdata_sourcesarray. - Search results: Databases return as
"object": "database"with adata_sourcesarray; capture thedata_source_idyou need for later writes and queries. - Parent in responses: Pages show
parent.data_source_idalongsideparent.database_id.
Notes
- Page/database IDs are UUIDs (with or without dashes).
- The API cannot set database view filters; that remains UI-only.
- Rate limit: ~3 requests/second average, with
429 rate_limitedresponses usingRetry-After. - Append block children: up to 100 children per request, up to two levels of nesting in a single append request.
- Payload size limits: up to 1000 block elements and 500KB overall.
- Use
is_inline: truewhen creating data sources to embed them in pages.