Notion API用于创建和管理页面、数据库及块。还包含想法点子库(💡)持久化工作流,当用户说「入库」「记录这个想法」「这个先记下来」「持久化这个」时触发。
Use the Notion API to create/read/update pages, databases, and blocks.
bash
mkdir -p ~/.config/notion
echo "ntn_your_key_here" > ~/.config/notion/api_key
Integration API key starts with ntn_ or secret_. Share target pages/databases with your integration (click "..." → "Connect to" → your integration name).
Critical: Wrong version = silent failures.
OperationVersionWhyQuery data source2025-09-03Newer endpointSearch / Get page2025-09-03Read operationsCreate/update pages2022-06-28More reliable for property writesCreate database2022-06-282025-09-03 silently drops custom propertiesUpdate database schema2022-06-28Same reason
Always include Notion-Version header. Default in this skill: 2025-09-03.
bash
NOTION_KEY=$(cat ~/.config/notion/api_key)
# Search
curl -s -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": "keywords"}'
# Get page
curl -s "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03"
# Query database (newer endpoint, use data_source_id)
curl -s -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 '{"sorts": [{"property": "创建时间", "direction": "descending"}], "page_size": 20}'
# Create page (use database_id as parent, version 2022-06-28)
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{"parent": {"database_id": "xxx"}, "properties": {"Name": {"title": [{"text": {"content": "Title"}}]}}}'
# Update page properties
curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{"properties": {"Status": {"select": {"name": "Done"}}}}'
Parse response (Python):
python
import subprocess, json
result = subprocess.run(['curl', '-s', ...], capture_output=True, text=True)
data = json.loads(result.stdout)
page_id = data.get('id')
error = data.get('message') # if 'object' == 'error'
数据库 ID: 339d8e39-9e68-814b-8fc9-c06adfb3ae00 里程碑数据库 ID: 339d8e39-9e68-8130-932c-ecf46af154b5 父页面: Winnie ( 321d8e39-9e68-8037-9c2f-d55fd4e9a54c)
字段类型说明名称title提纯后的标题,≤20字想法摘要rich_text核心内容摘要决策结论rich_text最终结论或后续行动(暂无填"待定")来源select临时想法 / 项目相关 / 系统讨论相关项目rich_text关联项目,可空标签multi_select自由标签状态select待实现 / 进行中 / 已规划 / 执行中 / 已实现 / 已归档规划内容rich_text想法→计划的推导过程(转为"已规划"时填写)相关里程碑relation反向关联里程碑条目里程碑数number关联里程碑计数重要性select高 / 中 / 低创建时间date消息时间戳(ISO 格式)
字段类型里程碑标题title所属想法relation → 想法点子库处理过程rich_text决策记录rich_text产物链接url状态select(进行中 / 已完成)创建时间date
python3 ~/.openclaw/skills/notion/scripts/notion-write-idea.py create < idea.jsony 确认 → 才写入 Notion不直接调 curl,统一走脚本确保确认环节:
bash
cat > /tmp/idea.json << 'EOF'
{
"名称": "无头服务器网站登录解法",
"想法摘要": "agent-browser在无头服务器无法登录需验证码网站。解法:Cookie导入、Xvfb虚拟显示器、本地登录导出session。",
"决策结论": "优先试方案1(Cookie导入),最可行。",
"来源": "临时想法",
"相关项目": "agent-browser",
"标签": ["服务器部署", "Cookie导入"],
"状态": "待实现",
"重要性": "中",
"创建时间": "2026-04-04T22:38:00+08:00"
}
EOF
python3 ~/.openclaw/skills/notion/scripts/notion-write-idea.py create < /tmp/idea.json
触发词: "转计划"、"开始规划"、"这是个好想法"
page_id规划内容 字段填入推导)bash
cat > /tmp/milestone.json << 'EOF'
{
"里程碑标题": "方案1测试:Cookie导入",
"所属想法ID": "想法页面的page_id",
"处理过程": "测试EditThisCookie导出Chrome Cookie,导入agent-browser",
"决策记录": "Cookie导入可行,但B站登录态有效期仅24h,需定期刷新",
"产物链接": "https://github.com/...",
"状态": "进行中",
"创建时间": "2026-04-05T13:00:00+08:00"
}
EOF
python3 ~/.openclaw/skills/notion/scripts/notion-write-milestone.py create < /tmp/milestone.json
触发词操作"已完成"/"已实现"状态→已实现"归档"/"不要了"状态→已归档"进行中"状态→进行中"转计划"/"开始规划"状态→已规划 + 填写规划内容"添加里程碑"在里程碑库创建条目
bash
curl -s -X POST "https://api.notion.com/v1/data_sources/339d8e39-9e68-814b-8fc9-c06adfb3ae00/query" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"sorts": [{"property": "创建时间", "direction": "descending"}], "page_size": 20}'
bash
curl -s -X POST "https://api.notion.com/v1/data_sources/339d8e39-9e68-8130-932c-ecf46af154b5/query" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"filter": {"property": "所属想法", "relation": {"contains": "想法page_id"}}}'
bash
curl -s -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": "keywords", "filter": {"value": "page", "property": "object"}}'
bash
curl -s "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03"
bash
curl -s "https://api.notion.com/v1/blocks/{page_id}/children" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03"
bash
curl -s -X POST "https://api.notion.com/v1/databases" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2022-06-28" \
-H "Content-Type: application/json" \
-d '{
"parent": {"type": "page_id", "page_id": "xxx"},
"title": [{"text": {"content": "Database Title"}}],
"properties": {
"Name": {"title": {}},
"Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}},
"Date": {"date": {}}
}
}'
bash
curl -s -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": "Text"}}]}}]}'
TypeFormatTitle{"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"}}Checkbox{"checkbox": true}Number{"number": 42}URL{"url": "https://..."}Relation{"relation": [{"id": "page_id"}]}
/data_sources/ endpoint; create uses /databasesdatabase_id (for creating pages) and data_source_id (for querying)2022-06-28 works reliably — 2025-09-03 silently drops custom properties2022-06-28 is more predictablepython
import subprocess, json
def notion_req(method, endpoint, body=None, version="2025-09-03"):
key = open("/root/.config/notion/api_key").read().strip()
cmd = ["curl", "-s", "-X", method,
f"https://api.notion.com/v1/{endpoint}",
"-H", f"Authorization: Bearer {key}",
"-H", f"Notion-Version: {version}",
"-H", "Content-Type: application/json"]
if body:
import json
cmd += ["-d", json.dumps(body)]
r = subprocess.run(cmd, capture_output=True, text=True)
data = json.loads(r.stdout)
if data.get("object") == "error":
raise Exception(f"Notion API error {data.get('code')}: {data.get('message')}")
return data
Common error codes:
object_not_found: 页面/数据库 ID 不存在或无权访问validation_error: 属性格式错误,检查 property type 是否匹配restricted_resource: 页面未分享给 integrationrate_limited: 限速,等 1 秒重试is_inline: true 可嵌入页面