com um clique
notion
Notion API for creating and managing pages, databases, and blocks.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Menu
Notion API for creating and managing pages, databases, and blocks.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Baseado na classificação ocupacional SOC
Transform course PDFs into page-by-page self-study lecture notes (Markdown) with AI review and optional Notion upload. Supports two courseware types: (1) Traditional section-based (physics/chemistry) with analogy→derivation→meaning path; (2) Slide-based (CS/AI) with problem→mechanism→application path. Uses MinerU API for high-fidelity extraction (VLM mode). Triggers: lecture notes, course notes, exam prep, 讲义, 课件讲解, 考点总结, 课程笔记, 从课件生成讲义, 分析课件, 上传讲义到Notion.
用 MinerU API 解析 PDF/Word/PPT/图片为 Markdown,支持公式、表格、OCR。适用于论文解析、文档提取。
| name | notion |
| description | Notion API for creating and managing pages, databases, and blocks. |
Use the Notion API to create/read/update pages, data sources (databases), and blocks.
ntn_ or secret_)mkdir -p ~/.config/notion
echo "ntn_your_key_here" > ~/.config/notion/api_key
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 the API.
⚠️ Deleting blocks is irreversible. Always follow these steps:
curl -X DELETE "https://api.notion.com/v1/blocks/{block_id}" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03"
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 page in a data source:
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": {"database_id": "xxx"},
"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"}]
}'
Create a data source (database):
curl -X POST "https://api.notion.com/v1/data_sources" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"parent": {"page_id": "xxx"},
"title": [{"text": {"content": "My Database"}}],
"properties": {
"Name": {"title": {}},
"Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}},
"Date": {"date": {}}
}
}'
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": [{"type": "text", "text": {"content": "Hello"}, "annotations": {"bold": true}}]}}
]
}'
⚠️ Tip: Use the
add_markdown_to_page.pyscript instead of writing JSON manually. It handles all inline formatting (bold, italic, code) automatically.
Common property formats for database items:
{"title": [{"text": {"content": "..."}}]}{"rich_text": [{"text": {"content": "..."}}]}{"select": {"name": "Option"}}{"multi_select": [{"name": "A"}, {"name": "B"}]}{"date": {"start": "2024-01-15", "end": "2024-01-16"}}{"checkbox": true}{"number": 42}{"url": "https://..."}{"email": "a@b.com"}{"relation": [{"id": "page_id"}]}/data_sources/ endpoints for queries and retrievaldatabase_id and a data_source_id
database_id when creating pages (parent: {"database_id": "..."})data_source_id when querying (POST /v1/data_sources/{id}/query)"object": "data_source" with their data_source_idparent.data_source_id alongside parent.database_idGET /v1/data_sources/{data_source_id}Notion supports inline formatting via annotations in rich_text objects:
{
"type": "text",
"text": {"content": "bold text"},
"annotations": {
"bold": true,
"italic": false,
"strikethrough": false,
"underline": false,
"code": false,
"color": "default"
}
For links: "text": {"content": "link text", "link": {"url": "https://..."}}
When adding markdown content to Notion, use this mapping:
| Markdown | Notion Block Type | Notes |
|---|---|---|
# Title | heading_1 | Use rich_text with annotations |
## Title | heading_2 | Level 1-6 supported |
### Title | heading_3 | ####, #####, ###### also work |
#### Title | heading_4 | Supported up to heading_6 |
- item | bulleted_list_item | Use rich_text with annotations |
1. item | numbered_list_item | Number auto-generated |
> quote | quote | Block quote |
--- | divider | Horizontal rule |
`code` | paragraph with code: true | Inline code via annotations |
```lang\ncode\n``` | code | Set language field |
<aside>...</aside> | callout with emoji 💡 | Set icon and color |
 | image | External URL or file upload |
$$\nexpression\n$$ | equation | Math block |
$expression$ | equation in rich_text | Inline math (within text) |
Parse these patterns and set annotations accordingly:
**text** → bold: true*text* → italic: true`code` → code: true~~text~~ → strikethrough: true[text](url) → link object$expression$ → {"type": "equation", "equation": {"expression": "..."}} (inline math, not a rich_text object — a separate object type in the rich_text array)Inline math $...$ is automatically parsed by parse_inline_formatting(). It generates a Notion equation inline object:
{"type": "equation", "equation": {"expression": "E(\\mathbf{k})"}}
This is different from block-level equations ($$...$$) which create standalone equation blocks. Inline equations are embedded within rich_text arrays alongside text objects.
Important: The $...$ pattern must not be confused with currency. The parser treats any $...$ with non-empty content as inline math.
Numbered list items have special nesting behavior:
numbered_list_item's rich_text (separated by newlines) to prevent numbering reset ```lang) under a numbered item are added as children of the numbered_list_item block, rendering as properly formatted nested codenumbered_list_item blocks auto-number; inserting any other block type between them resets the count to 1When modifying add_markdown_to_page.py, be aware of these critical patterns:
elif chain, not if — Each line type check must be elif (not if). Using if causes lines to match multiple conditions (e.g., a ``` line being added as both paragraph AND code block)continue after multi-line blocks — aside, code, table, and numbered_list all advance i internally. They must continue to skip the outer i += 1, otherwise lines get skipped or duplicatedTables require nested table_row children. Each row's cells is an array of rich_text arrays:
{
"type": "table",
"table": {
"table_width": 3,
"has_column_header": true,
"has_row_header": false,
"children": [
{"type": "table_row", "table_row": {"cells": [[{"type": "text", "text": {"content": "Header1"}}], [...], [...] ]}}
]
}
⚠️ LaTeX pipe protection: Table cells containing LaTeX \| (norm operator) are automatically protected before splitting on |. This prevents \|\nabla\| from being split into extra columns.
⚠️ Table limitation: You cannot append blocks to a page that already has a table block (validation error). Build table content in a separate script if needed.
After uploading, add_markdown_to_page.py automatically verifies the upload:
When upload fails partially:
WARNING: N/M chunks FAILED! with failed chunk indicesOn Windows PowerShell 5.1, Chinese characters may appear garbled in terminal output. This is a display-only issue — the Notion API data is correct.
Solution (built-in): All scripts automatically:
chcp 65001sys.stdout/sys.stderr with UTF-8 encodingPYTHONIOENCODING=utf-8 environment variableIf garbled output persists:
ensure_ascii=False and read it separatelyrepr() or .encode('ascii', 'backslashreplace') to see Unicode code pointsWhen a page needs to be cleared, archive and recreate is faster than deleting blocks one by one:
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 '{"archived": true}'
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": {"page_id": "parent_page_id"},
"properties": {"title": {"title": [{"text": {"content": "New Page Title"}}]}}
}'
Choose the right approach based on your situation:
When you have the correct content locally (e.g., markdown files), the safest approach is to archive old pages and create new ones with fresh content. This avoids duplication and ensures clean formatting.
When editing content that only exists on Notion (no local copy):
See scripts/ directory for reusable tools:
| Script | Purpose |
|---|---|
_notion_utils.py | Shared module: API helpers, formatting functions, constants (imported by all other scripts) |
add_markdown_to_page.py | Parse generic markdown file and add formatted blocks to a Notion page |
import_notion_export.py | Import Notion-exported markdown back to Notion with high fidelity (toggles, callouts, images, embeddings) |
export_page.py | Export Notion page (with sub-pages and databases) to local Markdown/CSV files |
archive_and_create_pages.py | Batch archive old pages and create new ones |
verify_page.py | Verify page content and formatting stats |
add_markdown_to_page.py — For generic Markdown files (blog posts, docs, READMEs). Broad format support, best-effort conversion.import_notion_export.py — For re-importing content exported by export_page.py. Preserves Notion-specific structures (toggles, callout emojis, image uploads, embeds, bookmarks). Use this for round-trip workflows.Add markdown to page (with proxy for China users):
# Bash/Linux/Mac:
export HTTP_PROXY=http://127.0.0.1:<your_proxy_port>
export HTTPS_PROXY=http://127.0.0.1:<your_proxy_port>
python scripts/add_markdown_to_page.py <page_id> "path/to/guide.md"
# PowerShell (Windows):
$env:HTTP_PROXY = "http://127.0.0.1:<your_proxy_port>"
$env:HTTPS_PROXY = "http://127.0.0.1:<your_proxy_port>"
python scripts/add_markdown_to_page.py <page_id> "path/to/guide.md"
Archive and recreate pages:
python scripts/archive_and_create_pages.py <parent_id> old_ids.txt titles.txt
Verify page formatting:
python scripts/verify_page.py <page_id>
Export page to local files:
python scripts/export_page.py <page_id>
python scripts/export_page.py <page_id> --output ./my_export
python scripts/export_page.py <page_id> --no-assets --no-csv
Import Notion export back to Notion:
# Import a single exported page
python scripts/import_notion_export.py <page_id> "D:\Export\Page Title\index.md"
# Import with recursive sub-pages from directory
python scripts/import_notion_export.py <parent_page_id> "D:\Export\Page Title" --recursive
Round-trip workflow (export → edit → re-import):
# 1. Export
python scripts/export_page.py <page_id> --output ./backup
# 2. Edit the markdown files locally
# 3. Archive old pages and create new ones
python scripts/archive_and_create_pages.py <parent_id> old_ids.txt titles.txt
# 4. Re-import with high fidelity
python scripts/import_notion_export.py <new_page_id> "./backup/Page Title" --recursive
Export output structure:
Page Title/
├── index.md # Page content as markdown
├── assets/ # Downloaded images/files
│ └── image.png
├── database_name.csv # Database as CSV
├── Sub Page Title/
│ └── index.md # Sub-page content (recursive)
└── Another Sub Page/
└── index.md
These scripts handle:
$...$ → equation inline objects in rich_text)\| pipe protection) as external blocks or file uploads)$$...$$ as equation blocks)import_notion_export.py)HTTPS_PROXY/HTTP_PROXY env vars)Retry-After header)If Notion API is unreachable directly (common in China), configure a proxy.
⚠️ Critical: add_markdown_to_page.py and other scripts read proxy from environment variables HTTP_PROXY and HTTPS_PROXY. These MUST be set before running the scripts.
# 替换为你的代理端口,如 10808, 7890 等
export HTTPS_PROXY=http://127.0.0.1:<your_proxy_port>
export HTTP_PROXY=http://127.0.0.1:<your_proxy_port>
python scripts/add_markdown_to_page.py <page_id> "file.md"
# 替换为你的代理端口
$env:HTTP_PROXY = "http://127.0.0.1:<your_proxy_port>"
$env:HTTPS_PROXY = "http://127.0.0.1:<your_proxy_port>"
python scripts/add_markdown_to_page.py <page_id> "file.md"
The _notion_utils.py module automatically reads these environment variables:
# In _notion_utils.py
PROXIES = {"https": os.environ.get("HTTPS_PROXY", ""),
"http": os.environ.get("HTTP_PROXY", "")}
If the environment variables are not set, scripts will attempt direct connection and may fail with ConnectionResetError.
import requests
# 替换为你的代理端口
proxies = {"https": "http://127.0.0.1:<your_proxy_port>", "http": "http://127.0.0.1:<your_proxy_port>"}
requests.get(url, headers=headers, proxies=proxies)
child_page blocks inside a toggle block via the APIchild_page block type is read-only — it appears when you create subpages in the UI/blocks/{toggle_block_id}/children429 and network errors429 rate_limited responses using Retry-Afteris_inline: true when creating data sources to embed them in pages