notion-sdk

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Notion SDK Skill

Notion SDK 技能

Control Notion programmatically using the official
notion-client
Python SDK. See PyPI for current version.
通过官方的
notion-client
Python SDK以编程方式控制Notion。查看PyPI获取最新版本。

When to Use This Skill

何时使用该技能

Use this skill when:
  • Creating pages or databases in Notion via API
  • Querying Notion databases programmatically
  • Adding blocks (text, code, headings) to Notion pages
  • Automating Notion workflows with Python
  • Integrating external data sources with Notion
在以下场景使用该技能:
  • 通过API在Notion中创建页面或数据库时
  • 以编程方式查询Notion数据库时
  • 向Notion页面添加内容块(文本、代码、标题)时
  • 使用Python自动化Notion工作流时
  • 将外部数据源与Notion集成时

Preflight: Token Collection

准备工作:收集令牌

Before any Notion API operation, collect the integration token:
AskUserQuestion(questions=[{
    "question": "Please provide your Notion Integration Token (starts with ntn_ or secret_)",
    "header": "Notion Token",
    "options": [
        {"label": "I have a token ready", "description": "Token from notion.so/my-integrations"},
        {"label": "Need to create one", "description": "Go to notion.so/my-integrations → New integration"}
    ],
    "multiSelect": false
}])
After user provides token:
  1. Validate format (must start with
    ntn_
    or
    secret_
    )
  2. Test with
    validate_token()
    from
    scripts/notion_wrapper.py
  3. Remind user: Each page/database must be shared with the integration
在进行任何Notion API操作前,先收集集成令牌:
AskUserQuestion(questions=[{
    "question": "Please provide your Notion Integration Token (starts with ntn_ or secret_)",
    "header": "Notion Token",
    "options": [
        {"label": "I have a token ready", "description": "Token from notion.so/my-integrations"},
        {"label": "Need to create one", "description": "Go to notion.so/my-integrations → New integration"}
    ],
    "multiSelect": false
}])
用户提供令牌后:
  1. 验证格式(必须以
    ntn_
    secret_
    开头)
  2. 使用
    scripts/notion_wrapper.py
    中的
    validate_token()
    进行测试
  3. 提醒用户:每个页面/数据库必须与集成应用共享

Quick Start

快速开始

1. Create a Page in Database

1. 在数据库中创建页面

python
from notion_client import Client
from scripts.create_page import (
    create_database_page,
    title_property,
    status_property,
    date_property,
)

client = Client(auth="ntn_...")
page = create_database_page(
    client,
    data_source_id="abc123...",  # Database ID
    properties={
        "Name": title_property("My New Task"),
        "Status": status_property("In Progress"),
        "Due Date": date_property("2025-12-31"),
    }
)
print(f"Created: {page['url']}")
python
from notion_client import Client
from scripts.create_page import (
    create_database_page,
    title_property,
    status_property,
    date_property,
)

client = Client(auth="ntn_...")
page = create_database_page(
    client,
    data_source_id="abc123...",  # Database ID
    properties={
        "Name": title_property("My New Task"),
        "Status": status_property("In Progress"),
        "Due Date": date_property("2025-12-31"),
    }
)
print(f"Created: {page['url']}")

2. Add Content Blocks

2. 添加内容块

python
from scripts.add_blocks import (
    append_blocks,
    heading,
    paragraph,
    bullet,
    code_block,
    callout,
)

blocks = [
    heading("Overview", level=2),
    paragraph("This page was created via the Notion API."),
    callout("Remember to share the page with your integration!", emoji="⚠️"),
    heading("Tasks", level=3),
    bullet("First task"),
    bullet("Second task"),
    code_block("print('Hello, Notion!')", language="python"),
]
append_blocks(client, page["id"], blocks)
python
from scripts.add_blocks import (
    append_blocks,
    heading,
    paragraph,
    bullet,
    code_block,
    callout,
)

blocks = [
    heading("Overview", level=2),
    paragraph("This page was created via the Notion API."),
    callout("Remember to share the page with your integration!", emoji="⚠️"),
    heading("Tasks", level=3),
    bullet("First task"),
    bullet("Second task"),
    code_block("print('Hello, Notion!')", language="python"),
]
append_blocks(client, page["id"], blocks)

3. Query Database

3. 查询数据库

python
from scripts.query_database import (
    query_data_source,
    checkbox_filter,
    status_filter,
    and_filter,
    sort_by_property,
)
python
from scripts.query_database import (
    query_data_source,
    checkbox_filter,
    status_filter,
    and_filter,
    sort_by_property,
)

Find incomplete high-priority items

Find incomplete high-priority items

results = query_data_source( client, data_source_id="abc123...", filter_obj=and_filter( checkbox_filter("Done", False), status_filter("Priority", "High") ), sorts=[sort_by_property("Due Date", "ascending")] ) for page in results: title = page["properties"]["Name"]["title"][0]["plain_text"] print(f"- {title}")
undefined
results = query_data_source( client, data_source_id="abc123...", filter_obj=and_filter( checkbox_filter("Done", False), status_filter("Priority", "High") ), sorts=[sort_by_property("Due Date", "ascending")] ) for page in results: title = page["properties"]["Name"]["title"][0]["plain_text"] print(f"- {title}")
undefined

Available Scripts

可用脚本

ScriptPurpose
notion_wrapper.py
Client setup, token validation, retry wrapper
create_page.py
Create pages, property builders
add_blocks.py
Append blocks, block type builders
query_database.py
Query, filter, sort, search
脚本名称用途
notion_wrapper.py
客户端设置、令牌验证、重试包装器
create_page.py
创建页面、属性构建器
add_blocks.py
追加内容块、内容块类型构建器
query_database.py
查询、过滤、排序、搜索

References

参考资料

  • Property Types - All 24 property types with examples
  • Block Types - All block types with structures
  • Rich Text - Formatting, links, mentions
  • Pagination - Handling large result sets
  • 属性类型 - 包含示例的全部24种属性类型
  • 内容块类型 - 包含结构的全部内容块类型
  • 富文本 - 格式设置、链接、提及
  • 分页 - 处理大型结果集

Important Constraints

重要限制

Rate Limits

速率限制

  • 3 requests/second average (burst tolerated briefly)
  • Use
    api_call_with_retry()
    for automatic rate limit handling
  • 429 responses include
    Retry-After
    header
  • 平均3次请求/秒(短暂的突发请求可容忍)
  • 使用
    api_call_with_retry()
    自动处理速率限制
  • 429响应包含
    Retry-After

Authentication Model

认证模型

  • Page-level sharing required (not workspace-wide)
  • User must explicitly add integration to each page/database:
    • Page → ... menu → Connections → Add connection → Select integration
  • 需要页面级共享(而非工作区级)
  • 用户必须显式将集成应用添加到每个页面/数据库:
    • 页面 → ...菜单 → 连接 → 添加连接 → 选择集成应用

API Version (v2.6.0+)

API版本(v2.6.0+)

  • Uses
    data_source_id
    instead of
    database_id
    for multi-source databases
  • Legacy
    database_id
    still works for simple databases
  • Scripts handle both patterns automatically
  • 使用
    data_source_id
    替代
    database_id
    以支持多源数据库
  • 旧版
    database_id
    仍适用于简单数据库
  • 脚本会自动处理两种模式

Operations NOT Supported

不支持的操作

  • Workspace settings modification
  • User permissions management
  • Template creation/management
  • Billing/subscription access
  • 修改工作区设置
  • 管理用户权限
  • 创建/管理模板
  • 访问计费/订阅信息

API Behavior Patterns

API行为模式

Insights discovered through integration testing (test citations for verification).
通过集成测试发现的洞察(可参考测试用例验证)。

Rate Limiting & Retry Logic

速率限制与重试逻辑

api_call_with_retry()
handles transient failures automatically:
Error TypeBehaviorWait Strategy
429 Rate LimitedRetriesRespects Retry-After header (default 1s)
500 Server ErrorRetriesExponential backoff: 1s, 2s, 4s
Auth/ValidationFails immediatelyNo retry
Citation:
test_client.py::TestRetryLogic
(lines 146-193)
api_call_with_retry()
会自动处理临时故障:
错误类型行为等待策略
429 速率受限重试遵循Retry-After头(默认1秒)
500 服务器错误重试指数退避:1秒、2秒、4秒
认证/验证错误立即失败不重试
Citation:
test_client.py::TestRetryLogic
(lines 146-193)

Read-After-Write Consistency

写后读一致性

Newly created blocks may not be immediately queryable. Add 0.5s minimum delay:
python
append_blocks(client, page_id, blocks)
time.sleep(0.5)  # Eventual consistency delay
children = client.blocks.children.list(page_id)
Citation:
test_integration.py::TestBlockAppend::test_retrieve_appended_blocks
(line 298)
新创建的内容块可能无法立即被查询到。添加至少0.5秒的延迟:
python
append_blocks(client, page_id, blocks)
time.sleep(0.5)  # Eventual consistency delay
children = client.blocks.children.list(page_id)
Citation:
test_integration.py::TestBlockAppend::test_retrieve_appended_blocks
(line 298)

v2.6.0 API Migration

v2.6.0 API迁移

Old PatternNew Pattern (v2.6.0+)
client.databases.query()
client.data_sources.query()
filter: {"value": "database"}
filter: {"value": "data_source"}
Citation:
test_integration.py::TestDatabaseQuery
(line 110)
旧模式新模式(v2.6.0+)
client.databases.query()
client.data_sources.query()
filter: {"value": "database"}
filter: {"value": "data_source"}
Citation:
test_integration.py::TestDatabaseQuery
(line 110)

Archive-Only Deletion

仅支持归档删除

Pages cannot be permanently deleted via API - only archived (moved to trash):
python
client.pages.update(page_id, archived=True)  # Trash, not delete
Citation:
test_integration.py
cleanup fixture (lines 72-76)
无法通过API永久删除页面——只能归档(移至回收站):
python
client.pages.update(page_id, archived=True)  # Trash, not delete
Citation:
test_integration.py
cleanup fixture (lines 72-76)

Edge Cases & Validation

边缘情况与验证

Property Builder Edge Cases

属性构建器边缘情况

InputBehaviorValid?
Empty string
""
Creates empty contentYes
Empty array
[]
Clears multi-select/relationsYes
None
for number
Clears property valueYes
Zero
0
Valid number (not falsy)Yes
Negative
-42
Valid numberYes
Unicode/emojiFully preservedYes
Citation:
test_property_builders.py::TestPropertyBuildersEdgeCases
(lines 302-341)
输入行为是否有效?
空字符串
""
创建空内容
空数组
[]
清除多选/关联属性
None
(数字类型)
清除属性值
数字
0
有效数字(非假值)
负数
-42
有效数字
Unicode/表情符号完全保留
Citation:
test_property_builders.py::TestPropertyBuildersEdgeCases
(lines 302-341)

Input Validation Responsibility

输入验证责任

Builders are intentionally permissive - validation happens at API level:
PropertyBuilder AcceptsAPI Validates
DateAny stringISO 8601 only
URLAny stringValid URL format
CheckboxTruthy valuesBoolean expected
Best Practice: Validate in your application before building properties.
Citation:
test_property_builders.py::TestPropertyBuildersInvalidInputs
(lines 347-376)
构建器设计为宽松模式——验证在API层面进行:
属性构建器接受的输入API验证规则
日期任意字符串仅支持ISO 8601格式
URL任意字符串有效的URL格式
复选框真值期望布尔值
最佳实践:在构建属性之前,先在你的应用中进行验证。
Citation:
test_property_builders.py::TestPropertyBuildersInvalidInputs
(lines 347-376)

Token Validation

令牌验证

  • Case-sensitive: Only lowercase
    ntn_
    and
    secret_
    valid
  • Format check happens before API call (saves unnecessary requests)
  • Empty/whitespace tokens rejected immediately
Citation:
test_client.py::TestClientEdgeCases
(lines 196-224)
  • 区分大小写:仅支持小写的
    ntn_
    secret_
    前缀
  • 在API调用前进行格式检查(避免不必要的请求)
  • 立即拒绝空值/仅含空白字符的令牌
Citation:
test_client.py::TestClientEdgeCases
(lines 196-224)

Query & Filter Patterns

查询与过滤模式

Compound Filter Composition

复合过滤器组合

python
undefined
python
undefined

Empty compound (matches all)

空复合过滤器(匹配所有内容)

and_filter() # {"and": []}
and_filter() # {"and": []}

Deep nesting supported

支持深度嵌套

and_filter( or_filter(filter_a, filter_b), and_filter(filter_c, filter_d) )

_Citation: `test_filter_builders.py::TestFilterEdgeCases` (lines 323-360)_
and_filter( or_filter(filter_a, filter_b), and_filter(filter_c, filter_d) )

_Citation: `test_filter_builders.py::TestFilterEdgeCases` (lines 323-360)_

Filter Limitations

过滤器限制

Filters don't exclude NULL properties - check in Python:
python
if row["properties"]["Rating"]["number"] is not None:
    # Process non-null values
Citation:
test_integration.py::TestDatabaseQuery::test_query_database_with_filter
(lines 120-135)
过滤器不会排除NULL属性——需在Python中检查:
python
if row["properties"]["Rating"]["number"] is not None:
    # Process non-null values
Citation:
test_integration.py::TestDatabaseQuery::test_query_database_with_filter
(lines 120-135)

Pagination Invariants

分页不变量

Condition
has_more
next_cursor
More results exist
True
Present, non-None
No more results
False
May be absent/None
Always check
has_more
before using
next_cursor
.
Citation:
test_integration.py::TestDatabaseQuery::test_query_database_with_pagination
(lines 137-151)
条件
has_more
next_cursor
存在更多结果
True
存在且非空
无更多结果
False
可能不存在/为空
始终在使用
next_cursor
之前检查
has_more
Citation:
test_integration.py::TestDatabaseQuery::test_query_database_with_pagination
(lines 137-151)

Error Handling

错误处理

python
from notion_client import APIResponseError, APIErrorCode

try:
    result = client.pages.create(...)
except APIResponseError as e:
    if e.code == APIErrorCode.ObjectNotFound:
        print("Page/database not found or not shared with integration")
    elif e.code == APIErrorCode.Unauthorized:
        print("Token invalid or expired")
    elif e.code == APIErrorCode.RateLimited:
        print(f"Rate limited. Retry after {e.additional_data.get('retry_after')}s")
    else:
        raise
python
from notion_client import APIResponseError, APIErrorCode

try:
    result = client.pages.create(...)
except APIResponseError as e:
    if e.code == APIErrorCode.ObjectNotFound:
        print("页面/数据库未找到或未与集成应用共享")
    elif e.code == APIErrorCode.Unauthorized:
        print("令牌无效或已过期")
    elif e.code == APIErrorCode.RateLimited:
        print(f"速率受限。请在{e.additional_data.get('retry_after')}秒后重试")
    else:
        raise

Installation

安装

bash
uv pip install notion-client  # v2.6+ required for data_source support
Or use PEP 723 inline dependencies (scripts include them).

bash
uv pip install notion-client  # 支持data_source需要v2.6+版本
或者使用PEP 723内联依赖(脚本已包含)。

Troubleshooting

故障排除

IssueCauseSolution
Object not foundPage not shared with integrationShare page: ... menu → Connections → Add integration
UnauthorizedToken invalid or expiredGenerate new token at notion.so/my-integrations
Rate limited (429)Too many requestsUse
api_call_with_retry()
for automatic handling
Empty results from queryFilter matches nothingVerify filter syntax and property names
Block not found after createEventual consistency delayAdd 0.5s delay after write before read
Invalid property typeWrong builder usedCheck property type in database schema
Token format rejectedWrong prefix (case-sensitive)Token must start with
ntn_
or
secret_
(lowercase)
Data source ID not workingOld API versionUpgrade notion-client to latest version
问题原因解决方案
对象未找到页面未与集成应用共享共享页面:...菜单 → 连接 → 添加集成应用
未授权令牌无效或已过期在notion.so/my-integrations生成新令牌
速率受限(429)请求过多使用
api_call_with_retry()
自动处理
查询返回空结果过滤器未匹配任何内容验证过滤器语法和属性名称
创建后找不到内容块最终一致性延迟写入后添加0.5秒延迟再进行读取
无效的属性类型使用了错误的构建器检查数据库架构中的属性类型
令牌格式被拒绝前缀错误(区分大小写)令牌必须以
ntn_
secret_
开头(小写)
数据源ID无法使用API版本过旧将notion-client升级到最新版本