Skip to main content سوق المهارات اكتشف واستكشف مهارات الذكاء الاصطناعي التي بناها المجتمع.
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
نسخ Promptعرض تفاصيل Prompt يتجاوز الأمر المباشر Prompt المخصّص للمراجعة. افحص المصدر قبل تشغيله.
npx skills add https://github.com/vamseeachanta/workspace-hub --skill notion-apiيبقى الأمر في سطر واحد. مرّر أفقيًا لمراجعته كاملًا قبل النسخ.
تفضّل نسخة محلية؟ نزّل الملفات المتاحة حاليًا لدى SkillsMP.
تحميل Zip جاري التحميل... Save/publish analysis or computation results from ANY ecosystem repo to Hugging Face as a queryable, viewer-renderable dataset. Use when the user wants to "save results to hugging face", "publish dataset to HF", "hugging face data saving", "save analysis results", "hf dataset", "make results queryable", or "render via datasets-server API". Reshapes nested results into flat parquet tables, writes a dataset card with a viewer `configs:` block and provenance, applies license/public-vs-private routing, enforces a domain data-quality gate (faithful-to-source != correct), publishes to `aceengineer/<repo>-<projection>`, and verifies via the datasets-server API.
المهن ذات الصلة SOC
استنادا إلى تصنيف SOC المهني
name notion-api version 1.0.0 description Notion API for workspace automation including databases, pages, blocks, query/filter syntax, and integration patterns author workspace-hub category productivity type skill capabilities ["database_operations","page_management","block_manipulation","query_filtering","property_types","relation_rollups","search_api","integration_patterns"] tools ["notion-api","notion-client","curl","jq"] tags ["notion","api","databases","pages","blocks","automation","productivity","workspace","integration"] platforms ["rest-api","python","javascript","web"] related_skills ["api-integration","todoist-api","obsidian","webhook-automation"]
Notion API Integration Skill
Master the Notion API for workspace automation, including databases, pages, blocks, query/filter syntax, and integration patterns. This skill covers the official REST API and Python SDK for building powerful Notion integrations.
When to Use This Skill
USE Notion API when:
Automating database entries and updates
Building custom dashboards from Notion data
Syncing data between Notion and external systems
Creating pages programmatically from templates
Querying databases with complex filters
Building integrations with other productivity tools
Generating reports from Notion databases
Implementing workflow automations
DON'T USE Notion API when:
Need real-time sync (API has rate limits)
Building chat/messaging features (use Slack API)
Need file storage solution (use dedicated storage)
Simple task management only (use Todoist API)
Need offline-first solution (use Obsidian)
Require sub-second response times
Prerequisites
Create Integration
1. Go to https://www.notion.so/my-integrations
2. Click "New integration"
3. Name: "My Integration"
4. Select workspace
5. Set capabilities (Read/Write content, etc.)
6. Copy the "Internal Integration Token"
Connect Integration to Pages
1. Open the Notion page/database you want to access
2. Click "..." menu (top right)
3. Click "Connections" > "Connect to" > Your integration
4. Integration can now access this page and children
Environment Setup
export NOTION_API_KEY="secret_xxxxxxxxxxxxxxxxxxxxx"
curl -s "https://api.notion.com/v1/users/me" \
-H "Authorization: Bearer $NOTION_API_KEY " \
-H "Notion-Version: 2022-06-28" | jq
Python SDK Installation
pip install notion-client
uv pip install notion-client
pip install python-dotenv requests
Verify Setup from notion_client import Client
import os
notion = Client(auth=os.environ["NOTION_API_KEY" ])
me = notion.users.me()
print (f"Connected as: {me['name' ]} " )
databases = notion.search(filter ={"property" : "object" , "value" : "database" })
print (f"Found {len (databases['results' ])} databases" )
Core Capabilities
1. Database Operations List and Search Databases:
curl -s -X POST "https://api.notion.com/v1/search" \
-H "Authorization: Bearer $NOTION_API_KEY " \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"property": "object",
"value": "database"
}
}' | jq '.results[] | {id: .id, title: .title[0].plain_text}'
curl -s "https://api.notion.com/v1/databases/DATABASE_ID" \
-H "Authorization: Bearer $NOTION_API_KEY " \
-H "Notion-Version: 2022-06-28" | jq '.properties'
Python - Database Operations:
from notion_client import Client
import os
notion = Client(auth=os.environ["NOTION_API_KEY" ])
results = notion.search(
filter ={"property" : "object" , "value" : "database" }
)
for db in results["results" ]:
title = db["title" ][0 ]["plain_text" ] if db["title" ] else "Untitled"
print (f"Database: {title} (ID: {db['id' ]} )" )
database = notion.databases.retrieve(database_id="your-database-id" )
print (f"Properties: {list (database['properties' ].keys())} " )
new_db = notion.databases.create(
parent={"type" : "page_id" , "page_id" : "parent-page-id" },
title=[{"type" : "text" , "text" : {"content" : "Tasks Database" }}],
properties={
"Name" : {"title" : {}},
"Status" : {
"select" : {
"options" : [
{"name" : "To Do" , "color" : "gray" },
{"name" : "In Progress" , "color" : "blue" },
{"name" : "Done" , "color" : "green" }
]
}
},
"Priority" : {
"select" : {
"options" : [
{"name" : "High" , "color" : "red" },
{"name" : "Medium" , "color" : "yellow" },
{"name" : "Low" , "color" : "gray" }
]
}
},
"Due Date" : {"date" : {}},
"Assignee" : {"people" : {}},
"Tags" : {"multi_select" : {"options" : []}},
"Completed" : {"checkbox" : {}},
"Notes" : {"rich_text" : {}}
}
)
print (f"Created database: {new_db['id' ]} " )
notion.databases.update(
database_id="your-database-id" ,
title=[{"type" : "text" , "text" : {"content" : "Updated Title" }}],
properties={
"New Property" : {"rich_text" : {}}
}
)
2. Query Databases
curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query" \
-H "Authorization: Bearer $NOTION_API_KEY " \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{}' | jq '.results'
curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query" \
-H "Authorization: Bearer $NOTION_API_KEY " \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{
"filter": {
"property": "Status",
"select": {
"equals": "In Progress"
}
}
}' | jq '.results'
curl -s -X POST "https://api.notion.com/v1/databases/DATABASE_ID/query" \
-H "Authorization: Bearer $NOTION_API_KEY " \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{
"sorts": [
{
"property": "Due Date",
"direction": "ascending"
}
]
}' | jq '.results'
Python - Query Operations:
results = notion.databases.query(database_id="your-database-id" )
for page in results["results" ]:
props = page["properties" ]
name = props["Name" ]["title" ][0 ]["plain_text" ] if props["Name" ]["title" ] else "Untitled"
print (f"- {name} " )
results = notion.databases.query(
database_id="your-database-id" ,
filter ={
"property" : "Status" ,
"select" : {
"equals" : "In Progress"
}
}
)
results = notion.databases.query(
database_id="your-database-id" ,
filter ={
"and" : [
{
"property" : "Status" ,
"select" : {"equals" : "In Progress" }
},
{
"property" : "Priority" ,
"select" : {"equals" : "High" }
}
]
}
)
results = notion.databases.query(
database_id="your-database-id" ,
filter ={
"or" : [
{"property" : "Status" , "select" : {"equals" : "To Do" }},
{"property" : "Status" , "select" : {"equals" : "In Progress" }}
]
}
)
results = notion.databases.query(
database_id="your-database-id" ,
sorts=[
{"property" : "Priority" , "direction" : "ascending" },
{"property" : "Due Date" , "direction" : "ascending" }
]
)
def query_all_pages (database_id, filter =None ):
"""Query all pages with pagination"""
all_results = []
has_more = True
start_cursor = None
while has_more:
response = notion.databases.query(
database_id=database_id,
filter =filter ,
start_cursor=start_cursor,
page_size=100
)
all_results.extend(response["results" ])
has_more = response["has_more" ]
start_cursor = response.get("next_cursor" )
return all_results
all_items = query_all_pages("your-database-id" )
print (f"Total items: {len (all_items)} " )
3. Filter Syntax Reference
{"property" : "Name" , "title" : {"equals" : "Exact Match" }}
{"property" : "Name" , "title" : {"does_not_equal" : "Not This" }}
{"property" : "Name" , "title" : {"contains" : "partial" }}
{"property" : "Name" , "title" : {"does_not_contain" : "exclude" }}
{"property" : "Name" , "title" : {"starts_with" : "Prefix" }}
{"property" : "Name" , "title" : {"ends_with" : "suffix" }}
{"property" : "Name" , "title" : {"is_empty" : True }}
{"property" : "Name" , "title" : {"is_not_empty" : True }}
{"property" : "Notes" , "rich_text" : {"contains" : "keyword" }}
{"property" : "Amount" , "number" : {"equals" : 100 }}
{"property" : "Amount" , "number" : {"does_not_equal" : 0 }}
{"property" : "Amount" , "number" : {"greater_than" : 50 }}
{"property" : "Amount" , "number" : {"less_than" : 100 }}
{"property" : "Amount" , "number" : {"greater_than_or_equal_to" : 10 }}
{"property" : "Amount" , "number" : {"less_than_or_equal_to" : 99 }}
{"property" : "Amount" , "number" : {"is_empty" : True }}
{"property" : "Amount" , "number" : {"is_not_empty" : True }}
{"property" : "Due Date" , "date" : {"equals" : "2025-01-17" }}
{"property" : "Due Date" , "date" : {"before" : "2025-01-20" }}
{"property" : "Due Date" , "date" : {"after" : "2025-01-10" }}
{"property" : "Due Date" , "date" : {"on_or_before" : "2025-01-17" }}
{"property" : "Due Date" , "date" : {"on_or_after" : "2025-01-01" }}
{"property" : "Due Date" , "date" : {"is_empty" : True }}
{"property" : "Due Date" , "date" : {"is_not_empty" : True }}
{"property" : "Due Date" , "date" : {"past_week" : {}}}
{"property" : "Due Date" , "date" : {"past_month" : {}}}
{"property" : "Due Date" , "date" : {"past_year" : {}}}
{"property" : "Due Date" , "date" : {"next_week" : {}}}
{"property" : "Due Date" , "date" : {"next_month" : {}}}
{"property" : "Due Date" , "date" : {"next_year" : {}}}
{"property" : "Due Date" , "date" : {"this_week" : {}}}
Select/Multi-Select Filters:
{"property" : "Status" , "select" : {"equals" : "Done" }}
{"property" : "Status" , "select" : {"does_not_equal" : "Done" }}
{"property" : "Status" , "select" : {"is_empty" : True }}
{"property" : "Status" , "select" : {"is_not_empty" : True }}
{"property" : "Tags" , "multi_select" : {"contains" : "urgent" }}
{"property" : "Tags" , "multi_select" : {"does_not_contain" : "archived" }}
{"property" : "Tags" , "multi_select" : {"is_empty" : True }}
{"property" : "Tags" , "multi_select" : {"is_not_empty" : True }}
{"property" : "Completed" , "checkbox" : {"equals" : True }}
{"property" : "Completed" , "checkbox" : {"equals" : False }}
Relation and Rollup Filters:
{"property" : "Project" , "relation" : {"contains" : "page-id" }}
{"property" : "Project" , "relation" : {"does_not_contain" : "page-id" }}
{"property" : "Project" , "relation" : {"is_empty" : True }}
{"property" : "Project" , "relation" : {"is_not_empty" : True }}
{"property" : "Total Tasks" , "rollup" : {"number" : {"greater_than" : 5 }}}
{"property" : "Completion" , "rollup" : {"number" : {"equals" : 100 }}}
{
"and" : [
{"property" : "Status" , "select" : {"equals" : "In Progress" }},
{"property" : "Priority" , "select" : {"equals" : "High" }},
{"property" : "Due Date" , "date" : {"before" : "2025-02-01" }}
]
}
{
"or" : [
{"property" : "Status" , "select" : {"equals" : "To Do" }},
{"property" : "Status" , "select" : {"equals" : "In Progress" }}
]
}
{
"and" : [
{
"or" : [
{"property" : "Priority" , "select" : {"equals" : "High" }},
{"property" : "Priority" , "select" : {"equals" : "Medium" }}
]
},
{"property" : "Status" , "select" : {"does_not_equal" : "Done" }}
]
}
4. Page Operations
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_API_KEY " \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{
"parent": {"database_id": "DATABASE_ID"},
"properties": {
"Name": {
"title": [{"text": {"content": "New Task"}}]
},
"Status": {
"select": {"name": "To Do"}
},
"Priority": {
"select": {"name": "High"}
},
"Due Date": {
"date": {"start": "2025-01-20"}
}
}
}' | jq
Python - Page Operations:
new_page = notion.pages.create(
parent={"database_id" : "your-database-id" },
properties={
"Name" : {
"title" : [{"text" : {"content" : "New Task" }}]
},
"Status" : {
"select" : {"name" : "To Do" }
},
"Priority" : {
"select" : {"name" : "High" }
},
"Due Date" : {
"date" : {"start" : "2025-01-20" , "end" : "2025-01-25" }
},
"Tags" : {
"multi_select" : [
{"name" : "development" },
{"name" : "urgent" }
]
},
"Assignee" : {
"people" : [{"id" : "user-id" }]
},
"Notes" : {
"rich_text" : [{"text" : {"content" : "Task description here" }}]
},
"Completed" : {
"checkbox" : False
},
"Amount" : {
"number" : 100
},
"URL" : {
"url" : "https://example.com"
},
"Email" : {
"email" : "user@example.com"
}
}
)
print (f"Created page: {new_page['id' ]} " )
new_page = notion.pages.create(
parent={"database_id" : "your-database-id" },
properties={
"Name" : {"title" : [{"text" : {"content" : "Page with Content" }}]}
},
children=[
{
"object" : "block" ,
"type" : "heading_2" ,
"heading_2" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Overview" }}]
}
},
{
"object" : "block" ,
"type" : "paragraph" ,
"paragraph" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "This is the content." }}]
}
},
{
"object" : "block" ,
"type" : "to_do" ,
"to_do" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Task item" }}],
"checked" : False
}
}
]
)
page = notion.pages.retrieve(page_id="page-id" )
print (f"Page: {page['properties' ]['Name' ]['title' ][0 ]['plain_text' ]} " )
notion.pages.update(
page_id="page-id" ,
properties={
"Status" : {"select" : {"name" : "Done" }},
"Completed" : {"checkbox" : True }
}
)
notion.pages.update(
page_id="page-id" ,
archived=True
)
notion.pages.update(
page_id="page-id" ,
archived=False
)
5. Block Operations
{
"type" : "paragraph" ,
"paragraph" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Text content" }}]
}
}
{
"type" : "heading_1" ,
"heading_1" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Heading 1" }}]
}
}
{
"type" : "bulleted_list_item" ,
"bulleted_list_item" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "List item" }}]
}
}
{
"type" : "numbered_list_item" ,
"numbered_list_item" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Item 1" }}]
}
}
{
"type" : "to_do" ,
"to_do" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Task" }}],
"checked" : False
}
}
{
"type" : "toggle" ,
"toggle" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Toggle header" }}],
"children" : []
}
}
{
"type" : "code" ,
"code" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "print('hello')" }}],
"language" : "python"
}
}
{
"type" : "quote" ,
"quote" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Quote text" }}]
}
}
{
"type" : "callout" ,
"callout" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Important note" }}],
"icon" : {"emoji" : "💡" }
}
}
{
"type" : "divider" ,
"divider" : {}
}
{
"type" : "table_of_contents" ,
"table_of_contents" : {}
}
Python - Block Operations:
blocks = notion.blocks.children.list (block_id="page-id" )
for block in blocks["results" ]:
print (f"Block type: {block['type' ]} " )
notion.blocks.children.append(
block_id="page-id" ,
children=[
{
"object" : "block" ,
"type" : "heading_2" ,
"heading_2" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "New Section" }}]
}
},
{
"object" : "block" ,
"type" : "paragraph" ,
"paragraph" : {
"rich_text" : [
{"type" : "text" , "text" : {"content" : "Some " }},
{"type" : "text" , "text" : {"content" : "bold" }, "annotations" : {"bold" : True }},
{"type" : "text" , "text" : {"content" : " text." }}
]
}
},
{
"object" : "block" ,
"type" : "bulleted_list_item" ,
"bulleted_list_item" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "First item" }}]
}
},
{
"object" : "block" ,
"type" : "bulleted_list_item" ,
"bulleted_list_item" : {
"rich_text" : [{"type" : "text" , "text" : {"content" : "Second item" }}]
}
}
]
)
notion.blocks.update(
block_id="block-id" ,
paragraph={
"rich_text" : [{"type" : "text" , "text" : {"content" : "Updated content" }}]
}
)
notion.blocks.delete(block_id="block-id" )
def get_all_blocks (block_id ):
"""Recursively get all blocks"""
all_blocks = []
has_more = True
start_cursor = None
while has_more:
response = notion.blocks.children.list (
block_id=block_id,
start_cursor=start_cursor,
page_size=100
)
for block in response["results" ]:
all_blocks.append(block)
if block.get("has_children" ):
children = get_all_blocks(block["id" ])
all_blocks.extend(children)
has_more = response["has_more" ]
start_cursor = response.get("next_cursor" )
return all_blocks
all_blocks = get_all_blocks("page-id" )
print (f"Total blocks: {len (all_blocks)} " )
6. Rich Text Formatting
{"type" : "text" , "text" : {"content" : "Plain text" }}
{
"type" : "text" ,
"text" : {"content" : "Styled text" },
"annotations" : {
"bold" : True ,
"italic" : False ,
"strikethrough" : False ,
"underline" : False ,
"code" : False ,
"color" : "red"
}
}
{
"type" : "text" ,
"text" : {
"content" : "Click here" ,
"link" : {"url" : "https://example.com" }
}
}
{
"type" : "mention" ,
"mention" : {
"type" : "user" ,
"user" : {"id" : "user-id" }
}
}
{
"type" : "mention" ,
"mention" : {
"type" : "page" ,
"page" : {"id" : "page-id" }
}
}
{
"type" : "mention" ,
"mention" : {
"type" : "date" ,
"date" : {"start" : "2025-01-17" }
}
}
{
"type" : "equation" ,
"equation" : {"expression" : "E = mc^2" }
}
Python - Rich Text Helper:
def create_rich_text (text, bold=False , italic=False , code=False , color="default" , link=None ):
"""Helper to create rich text objects"""
rt = {
"type" : "text" ,
"text" : {"content" : text},
"annotations" : {
"bold" : bold,
"italic" : italic,
"strikethrough" : False ,
"underline" : False ,
"code" : code,
"color" : color
}
}
if link:
rt["text" ]["link" ] = {"url" : link}
return rt
paragraph_content = [
create_rich_text("This is " ),
create_rich_text("bold" , bold=True ),
create_rich_text(" and " ),
create_rich_text("italic" , italic=True ),
create_rich_text(" text with a " ),
create_rich_text("link" , link="https://example.com" ),
create_rich_text("." )
]
notion.blocks.children.append(
block_id="page-id" ,
children=[{
"type" : "paragraph" ,
"paragraph" : {"rich_text" : paragraph_content}
}]
)
7. Relations and Rollups Create Related Databases:
projects_db = notion.databases.create(
parent={"type" : "page_id" , "page_id" : "parent-page-id" },
title=[{"type" : "text" , "text" : {"content" : "Projects" }}],
properties={
"Name" : {"title" : {}},
"Status" : {
"select" : {
"options" : [
{"name" : "Active" , "color" : "green" },
{"name" : "Completed" , "color" : "gray" }
]
}
}
}
)
tasks_db = notion.databases.create(
parent={"type" : "page_id" , "page_id" : "parent-page-id" },
title=[{"type" : "text" , "text" : {"content" : "Tasks" }}],
properties={
"Name" : {"title" : {}},
"Status" : {
"select" : {
"options" : [
{"name" : "To Do" , "color" : "gray" },
{"name" : "Done" , "color" : "green" }
]
}
},
"Project" : {
"relation" : {
"database_id" : projects_db["id" ],
"single_property" : {}
}
}
}
)
notion.databases.update(
database_id=projects_db["id" ],
properties={
"Task Count" : {
"rollup" : {
"relation_property_name" : "Tasks" ,
"rollup_property_name" : "Name" ,
"function" : "count"
}
}
}
)
notion.pages.create(
parent={"database_id" : tasks_db["id" ]},
properties={
"Name" : {"title" : [{"text" : {"content" : "Task 1" }}]},
"Status" : {"select" : {"name" : "To Do" }},
"Project" : {"relation" : [{"id" : "project-page-id" }]}
}
)
8. Search API
results = notion.search()
print (f"Total accessible items: {len (results['results' ])} " )
results = notion.search(query="project plan" )
for item in results["results" ]:
obj_type = item["object" ]
if obj_type == "page" :
title = item["properties" ].get("title" , {}).get("title" , [{}])[0 ].get("plain_text" , "Untitled" )
elif obj_type == "database" :
title = item["title" ][0 ]["plain_text" ] if item["title" ] else "Untitled"
print (f"{obj_type} : {title} " )
results = notion.search(
query="meeting" ,
filter ={"property" : "object" , "value" : "page" }
)
results = notion.search(
filter ={"property" : "object" , "value" : "database" }
)
results = notion.search(
query="report" ,
sort={
"direction" : "descending" ,
"timestamp" : "last_edited_time"
}
)
def search_all (query=None , filter =None ):
"""Search with pagination"""
all_results = []
has_more = True
start_cursor = None
while has_more:
response = notion.search(
query=query,
filter =filter ,
start_cursor=start_cursor,
page_size=100
)
all_results.extend(response["results" ])
has_more = response["has_more" ]
start_cursor = response.get("next_cursor" )
return all_results
Complete Examples
Example 1: Task Management System
"""notion_tasks.py - Complete task management with Notion"""
from notion_client import Client
from datetime import datetime, timedelta
import os
notion = Client(auth=os.environ["NOTION_API_KEY" ])
class NotionTaskManager :
def __init__ (self, database_id ):
self .database_id = database_id
def create_task (self, name, status="To Do" , priority="Medium" ,
due_date=None , tags=None , notes=None ):
"""Create a new task"""
properties = {
"Name" : {"title" : [{"text" : {"content" : name}}]},
"Status" : {"select" : {"name" : status}},
"Priority" : {"select" : {"name" : priority}}
}
if due_date:
properties["Due Date" ] = {"date" : {"start" : due_date}}
if tags:
properties["Tags" ] = {
"multi_select" : [{"name" : tag} for tag in tags]
}
if notes:
properties["Notes" ] = {
"rich_text" : [{"text" : {"content" : notes}}]
}
return notion.pages.create(
parent={"database_id" : self .database_id},
properties=properties
)
def get_tasks_by_status (self, status ):
"""Get all tasks with given status"""
return notion.databases.query(
database_id=self .database_id,
filter ={
"property" : "Status" ,
"select" : {"equals" : status}
}
)
def get_overdue_tasks (self ):
"""Get all overdue tasks"""
today = datetime.now().strftime("%Y-%m-%d" )
return notion.databases.query(
database_id=self .database_id,
filter ={
"and" : [
{"property" : "Due Date" , "date" : {"before" : today}},
{"property" : "Status" , "select" : {"does_not_equal" : "Done" }}
]
}
)
def get_high_priority_tasks (self ):
"""Get high priority incomplete tasks"""
return notion.databases.query(
database_id=self .database_id,
filter ={
"and" : [
{"property" : "Priority" , "select" : {"equals" : "High" }},
{"property" : "Status" , "select" : {"does_not_equal" : "Done" }}
]
},
sorts=[
{"property" : "Due Date" , "direction" : "ascending" }
]
)
def complete_task (self, page_id ):
"""Mark task as done"""
return notion.pages.update(
page_id=page_id,
properties={
"Status" : {"select" : {"name" : "Done" }},
"Completed" : {"checkbox" : True }
}
)
def update_task_status (self, page_id, status ):
"""Update task status"""
return notion.pages.update(
page_id=page_id,
properties={
"Status" : {"select" : {"name" : status}}
}
)
def get_weekly_summary (self ):
"""Get summary for the week"""
week_ago = (datetime.now() - timedelta(days=7 )).strftime("%Y-%m-%d" )
completed = notion.databases.query(
database_id=self .database_id,
filter ={
"and" : [
{"property" : "Status" , "select" : {"equals" : "Done" }},
{"property" : "Last edited time" , "date" : {"after" : week_ago}}
]
}
)
next_week = (datetime.now() + timedelta(days=7 )).strftime("%Y-%m-%d" )
upcoming = notion.databases.query(
database_id=self .database_id,
filter ={
"and" : [
{"property" : "Due Date" , "date" : {"on_or_before" : next_week}},
{"property" : "Status" , "select" : {"does_not_equal" : "Done" }}
]
}
)
return {
"completed_count" : len (completed["results" ]),
"upcoming_count" : len (upcoming["results" ]),
"completed" : completed["results" ],
"upcoming" : upcoming["results" ]
}
if __name__ == "__main__" :
tm = NotionTaskManager("your-database-id" )
task = tm.create_task(
name="Review Q1 report" ,
priority="High" ,
due_date="2025-01-20" ,
tags=["work" , "quarterly" ],
notes="Review and provide feedback"
)
print (f"Created task: {task['id' ]} " )
overdue = tm.get_overdue_tasks()
print (f"\nOverdue tasks: {len (overdue['results' ])} " )
for t in overdue["results" ]:
name = t["properties" ]["Name" ]["title" ][0 ]["plain_text" ]
print (f" - {name} " )
summary = tm.get_weekly_summary()
print (f"\nWeekly Summary:" )
print (f" Completed: {summary['completed_count' ]} " )
print (f" Upcoming: {summary['upcoming_count' ]} " )
Example 2: Content Management System
"""notion_cms.py - Content management with Notion"""
from notion_client import Client
from datetime import datetime
import os
notion = Client(auth=os.environ["NOTION_API_KEY" ])
class NotionCMS :
def __init__ (self, content_db_id, categories_db_id=None ):
self .content_db_id = content_db_id
self .categories_db_id = categories_db_id
def create_article (self, title, content_blocks, status="Draft" ,
category=None , tags=None , author=None ):
"""Create a new article"""
properties = {
"Title" : {"title" : [{"text" : {"content" : title}}]},
"Status" : {"select" : {"name" : status}},
"Created" : {"date" : {"start" : datetime.now().isoformat()}}
}
if category:
properties["Category" ] = {"select" : {"name" : category}}
if tags:
properties["Tags" ] = {
"multi_select" : [{"name" : tag} for tag in tags]
}
if author:
properties["Author" ] = {
"rich_text" : [{"text" : {"content" : author}}]
}
return notion.pages.create(
parent={"database_id" : self .content_db_id},
properties=properties,
children=content_blocks
)
def create_article_with_template (self, title, template="blog" ):
"""Create article from template"""
templates = {
"blog" : [
{"type" : "heading_2" , "heading_2" : {"rich_text" : [{"text" : {"content" : "Introduction" }}]}},
{"type" : "paragraph" , "paragraph" : {"rich_text" : [{"text" : {"content" : "" }}]}},
{"type" : "heading_2" , "heading_2" : {"rich_text" : [{"text" : {"content" : "Main Content" }}]}},
{"type" : "paragraph" , "paragraph" : {"rich_text" : [{"text" : {"content" : "" }}]}},
{"type" : "heading_2" , "heading_2" : {"rich_text" : [{"text" : {"content" : "Conclusion" }}]}},
{"type" : "paragraph" , "paragraph" : {"rich_text" : [{"text" : {"content" : "" }}]}},
],
"tutorial" : [
{"type" : "callout" , "callout" : {
"rich_text" : [{"text" : {"content" : "Prerequisites: " }}],
"icon" : {"emoji" : "📋" }
}},
{"type" : "heading_2" , "heading_2" : {"rich_text" : [{"text" : {"content" : "Overview" }}]}},
{"type" : "paragraph" , "paragraph" : {"rich_text" : [{"text" : {"content" : "" }}]}},
{"type" : "heading_2" , "heading_2" : {"rich_text" : [{"text" : {"content" : "Step 1" }}]}},
{"type" : "paragraph" , "paragraph" : {"rich_text" : [{"text" : {"content" : "" }}]}},
{"type" : "code" , "code" : {"rich_text" : [{"text" : {"content" : "# code here" }}], "language" : "python" }},
{"type" : "heading_2" , "heading_2" : {"rich_text" : [{"text" : {"content" : "Step 2" }}]}},
{"type" : "paragraph" , "paragraph" : {"rich_text" : [{"text" : {"content" : "" }}]}},
{"type" : "heading_2" , "heading_2" : {"rich_text" : [{"text" : {"content" : "Summary" }}]}},
{"type" : "paragraph" , "paragraph" : {"rich_text" : [{"text" : {"content" : "" }}]}},
]
}
return self .create_article(
title=title,
content_blocks=templates.get(template, templates["blog" ]),
status="Draft"
)
def get_published_articles (self, category=None , limit=10 ):
"""Get published articles"""
filter_conditions = [
{"property" : "Status" , "select" : {"equals" : "Published" }}
]
if category:
filter_conditions.append(
{"property" : "Category" , "select" : {"equals" : category}}
)
return notion.databases.query(
database_id=self .content_db_id,
filter ={"and" : filter_conditions} if len (filter_conditions) > 1 else filter_conditions[0 ],
sorts=[{"property" : "Created" , "direction" : "descending" }],
page_size=limit
)
def publish_article (self, page_id ):
"""Publish an article"""
return notion.pages.update(
page_id=page_id,
properties={
"Status" : {"select" : {"name" : "Published" }},
"Published Date" : {"date" : {"start" : datetime.now().isoformat()}}
}
)
def export_article_to_markdown (self, page_id ):
"""Export article content to markdown"""
page = notion.pages.retrieve(page_id)
blocks = notion.blocks.children.list (block_id=page_id)
title = page["properties" ]["Title" ]["title" ][0 ]["plain_text" ]
markdown = f"# {title} \n\n"
for block in blocks["results" ]:
markdown += self ._block_to_markdown(block)
return markdown
def _block_to_markdown (self, block ):
"""Convert block to markdown"""
block_type = block["type" ]
if block_type == "paragraph" :
text = self ._rich_text_to_markdown(block["paragraph" ]["rich_text" ])
return f"{text} \n\n"
elif block_type == "heading_1" :
text = self ._rich_text_to_markdown(block["heading_1" ]["rich_text" ])
return f"# {text} \n\n"
elif block_type == "heading_2" :
text = self ._rich_text_to_markdown(block["heading_2" ]["rich_text" ])
return f"## {text} \n\n"
elif block_type == "heading_3" :
text = self ._rich_text_to_markdown(block["heading_3" ]["rich_text" ])
return f"### {text} \n\n"
elif block_type == "bulleted_list_item" :
text = self ._rich_text_to_markdown(block["bulleted_list_item" ]["rich_text" ])
return f"- {text} \n"
elif block_type == "numbered_list_item" :
text = self ._rich_text_to_markdown(block["numbered_list_item" ]["rich_text" ])
return f"1. {text} \n"
elif block_type == "code" :
text = self ._rich_text_to_markdown(block["code" ]["rich_text" ])
lang = block["code" ]["language" ]
return f"```{lang} \n{text} \n```\n\n"
elif block_type == "quote" :
text = self ._rich_text_to_markdown(block["quote" ]["rich_text" ])
return f"> {text} \n\n"
elif block_type == "divider" :
return "---\n\n"
return ""
def _rich_text_to_markdown (self, rich_text ):
"""Convert rich text array to markdown"""
result = ""
for rt in rich_text:
text = rt.get("text" , {}).get("content" , "" )
annotations = rt.get("annotations" , {})
if annotations.get("bold" ):
text = f"**{text} **"
if annotations.get("italic" ):
text = f"*{text} *"
if annotations.get("code" ):
text = f"`{text} `"
if annotations.get("strikethrough" ):
text = f"~~{text} ~~"
link = rt.get("text" , {}).get("link" )
if link:
text = f"[{text} ]({link['url' ]} )"
result += text
return result
if __name__ == "__main__" :
cms = NotionCMS("your-content-database-id" )
article = cms.create_article_with_template(
title="Getting Started with Python" ,
template="tutorial"
)
print (f"Created article: {article['id' ]} " )
published = cms.get_published_articles(limit=5 )
print (f"\nPublished articles: {len (published['results' ])} " )
md = cms.export_article_to_markdown("article-page-id" )
print (md)
Example 3: Project Dashboard
"""notion_dashboard.py - Project dashboard with Notion"""
from notion_client import Client
from datetime import datetime, timedelta
import os
notion = Client(auth=os.environ["NOTION_API_KEY" ])
def generate_project_dashboard (projects_db_id, tasks_db_id ):
"""Generate project dashboard data"""
projects = notion.databases.query(
database_id=projects_db_id,
filter ={
"property" : "Status" ,
"select" : {"equals" : "Active" }
}
)
dashboard_data = []
for project in projects["results" ]:
project_id = project["id" ]
project_name = project["properties" ]["Name" ]["title" ][0 ]["plain_text" ]
tasks = notion.databases.query(
database_id=tasks_db_id,
filter ={
"property" : "Project" ,
"relation" : {"contains" : project_id}
}
)
total_tasks = len (tasks["results" ])
completed = sum (1 for t in tasks["results" ]
if t["properties" ]["Status" ]["select" ]["name" ] == "Done" )
in_progress = sum (1 for t in tasks["results" ]
if t["properties" ]["Status" ]["select" ]["name" ] == "In Progress" )
today = datetime.now().strftime("%Y-%m-%d" )
overdue = sum (1 for t in tasks["results" ]
if t["properties" ].get("Due Date" , {}).get("date" , {}).get("start" , "9999-99-99" ) < today
and t["properties" ]["Status" ]["select" ]["name" ] != "Done" )
dashboard_data.append({
"project_id" : project_id,
"project_name" : project_name,
"total_tasks" : total_tasks,
"completed" : completed,
"in_progress" : in_progress,
"pending" : total_tasks - completed - in_progress,
"overdue" : overdue,
"completion_rate" : round (completed / total_tasks * 100 , 1 ) if total_tasks > 0 else 0
})
return dashboard_data
def create_dashboard_page (parent_page_id, dashboard_data ):
"""Create a dashboard page with metrics"""
blocks = [
{
"type" : "heading_1" ,
"heading_1" : {
"rich_text" : [{"text" : {"content" : f"Project Dashboard - {datetime.now().strftime('%Y-%m-%d' )} " }}]
}
},
{
"type" : "divider" ,
"divider" : {}
}
]
for project in dashboard_data:
blocks.extend([
{
"type" : "heading_2" ,
"heading_2" : {
"rich_text" : [{"text" : {"content" : project["project_name" ]}}]
}
},
{
"type" : "callout" ,
"callout" : {
"rich_text" : [{
"text" : {
"content" : f"Completion: {project['completion_rate' ]} % | "
f"Tasks: {project['completed' ]} /{project['total_tasks' ]} | "
f"In Progress: {project['in_progress' ]} | "
f"Overdue: {project['overdue' ]} "
}
}],
"icon" : {"emoji" : "📊" }
}
}
])
progress = int (project['completion_rate' ] / 10 )
progress_bar = "🟩" * progress + "⬜" * (10 - progress)
blocks.append({
"type" : "paragraph" ,
"paragraph" : {
"rich_text" : [{"text" : {"content" : f"Progress: {progress_bar} " }}]
}
})
return notion.pages.create(
parent={"page_id" : parent_page_id},
properties={
"title" : {"title" : [{"text" : {"content" : "Project Dashboard" }}]}
},
children=blocks
)
if __name__ == "__main__" :
data = generate_project_dashboard(
projects_db_id="projects-database-id" ,
tasks_db_id="tasks-database-id"
)
print ("Project Dashboard" )
print ("=" * 50 )
for project in data:
print (f"\n{project['project_name' ]} " )
print (f" Completion: {project['completion_rate' ]} %" )
print (f" Tasks: {project['completed' ]} /{project['total_tasks' ]} " )
print (f" In Progress: {project['in_progress' ]} " )
print (f" Overdue: {project['overdue' ]} " )
Integration Examples
Integration with Slack
"""slack_notion.py - Sync Slack messages to Notion"""
import os
import requests
from notion_client import Client
notion = Client(auth=os.environ["NOTION_API_KEY" ])
SLACK_WEBHOOK = os.environ["SLACK_WEBHOOK_URL" ]
def notify_slack_on_page_update (page_id, message ):
"""Send Slack notification when Notion page is updated"""
page = notion.pages.retrieve(page_id)
title = page["properties" ]["Name" ]["title" ][0 ]["plain_text" ]
payload = {
"blocks" : [
{
"type" : "section" ,
"text" : {
"type" : "mrkdwn" ,
"text" : f"*Notion Update*: {title} \n{message} "
}
},
{
"type" : "actions" ,
"elements" : [{
"type" : "button" ,
"text" : {"type" : "plain_text" , "text" : "View in Notion" },
"url" : page["url" ]
}]
}
]
}
requests.post(SLACK_WEBHOOK, json=payload)
def create_notion_page_from_slack (database_id, title, content, channel ):
"""Create Notion page from Slack message"""
return notion.pages.create(
parent={"database_id" : database_id},
properties={
"Name" : {"title" : [{"text" : {"content" : title}}]},
"Source" : {"select" : {"name" : "Slack" }},
"Channel" : {"rich_text" : [{"text" : {"content" : channel}}]}
},
children=[{
"type" : "paragraph" ,
"paragraph" : {
"rich_text" : [{"text" : {"content" : content}}]
}
}]
)
Integration with GitHub
"""github_notion.py - Sync GitHub issues to Notion"""
import os
import requests
from notion_client import Client
notion = Client(auth=os.environ["NOTION_API_KEY" ])
GITHUB_TOKEN = os.environ["GITHUB_TOKEN" ]
def sync_github_issues_to_notion (repo, database_id ):
"""Sync GitHub issues to Notion database"""
response = requests.get(
f"https://api.github.com/repos/{repo} /issues" ,
headers={"Authorization" : f"token {GITHUB_TOKEN} " }
)
issues = response.json()
for issue in issues:
existing = notion.databases.query(
database_id=database_id,
filter ={
"property" : "GitHub ID" ,
"number" : {"equals" : issue["number" ]}
}
)
properties = {
"Name" : {"title" : [{"text" : {"content" : issue["title" ]}}]},
"GitHub ID" : {"number" : issue["number" ]},
"Status" : {
"select" : {"name" : "Open" if issue["state" ] == "open" else "Closed" }
},
"URL" : {"url" : issue["html_url" ]},
"Labels" : {
"multi_select" : [{"name" : l["name" ]} for l in issue["labels" ]]
}
}
if existing["results" ]:
notion.pages.update(
page_id=existing["results" ][0 ]["id" ],
properties=properties
)
else :
notion.pages.create(
parent={"database_id" : database_id},
properties=properties,
children=[{
"type" : "paragraph" ,
"paragraph" : {
"rich_text" : [{"text" : {"content" : issue.get("body" , "" ) or "" }}]
}
}]
)
print (f"Synced {len (issues)} issues from {repo} " )
Best Practices
1. Rate Limiting import time
from functools import wraps
def rate_limit (calls_per_second=3 ):
"""Decorator to rate limit API calls"""
min_interval = 1.0 / calls_per_second
last_called = [0.0 ]
def decorator (func ):
@wraps(func )
def wrapper (*args, **kwargs ):
elapsed = time.time() - last_called[0 ]
wait_time = min_interval - elapsed
if wait_time > 0 :
time.sleep(wait_time)
result = func(*args, **kwargs)
last_called[0 ] = time.time()
return result
return wrapper
return decorator
@rate_limit(calls_per_second=3 )
def api_call (func, *args, **kwargs ):
return func(*args, **kwargs)
2. Error Handling from notion_client import APIResponseError
def safe_notion_call (func, *args, max_retries=3 , **kwargs ):
"""Execute Notion API call with retry logic"""
for attempt in range (max_retries):
try :
return func(*args, **kwargs)
except APIResponseError as e:
if e.status == 429 :
wait_time = int (e.headers.get("Retry-After" , 60 ))
print (f"Rate limited. Waiting {wait_time} s..." )
time.sleep(wait_time)
elif e.status >= 500 :
time.sleep(2 ** attempt)
else :
raise
except Exception as e:
if attempt < max_retries - 1 :
time.sleep(2 ** attempt)
else :
raise
raise Exception(f"Failed after {max_retries} retries" )
3. Batch Operations def batch_create_pages (database_id, pages_data, batch_size=10 ):
"""Create pages in batches to avoid rate limits"""
results = []
for i in range (0 , len (pages_data), batch_size):
batch = pages_data[i:i + batch_size]
for page_data in batch:
result = notion.pages.create(
parent={"database_id" : database_id},
properties=page_data["properties" ],
children=page_data.get("children" , [])
)
results.append(result)
if i + batch_size < len (pages_data):
time.sleep(1 )
return results
4. Caching import json
from pathlib import Path
from datetime import datetime, timedelta
CACHE_DIR = Path.home() / ".cache" / "notion"
CACHE_TTL = timedelta(minutes=5 )
def get_cached_or_fetch (key, fetch_func, ttl=CACHE_TTL ):
"""Get from cache or fetch fresh data"""
CACHE_DIR.mkdir(parents=True , exist_ok=True )
cache_file = CACHE_DIR / f"{key} .json"
if cache_file.exists():
data = json.loads(cache_file.read_text())
cached_at = datetime.fromisoformat(data["cached_at" ])
if datetime.now() - cached_at < ttl:
return data["value" ]
value = fetch_func()
cache_data = {
"cached_at" : datetime.now().isoformat(),
"value" : value
}
cache_file.write_text(json.dumps(cache_data, default=str ))
return value
Troubleshooting
Common Issues
curl -s "https://api.notion.com/v1/users/me" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2022-06-28"
Issue: Rate limiting (429)
Version History Version Date Changes 1.0.0 2025-01-17 Initial release with comprehensive Notion API coverage
Resources
This skill enables powerful workspace automation through Notion's comprehensive API, supporting databases, pages, blocks, queries, and integration patterns.