notion – Coding skill for AI agents
Notion API + ntn CLI: pages, databases, markdown, Workers.
Install the notion skill with one command
Pick the tool you use, copy the command and paste it in your terminal. The skill lands in that tool's skills folder and is ready in your next session.
Claude Code
mkdir -p ~/.claude/skills && curl -fsSL https://skill.dn1nguoi.com/z/notion-fa10a.tgz | tar xz -C ~/.claude/skills
Call it in Claude Code: /notion – then describe the task you want done.
Codex
mkdir -p ~/.codex/skills && curl -fsSL https://skill.dn1nguoi.com/z/notion-fa10a.tgz | tar xz -C ~/.codex/skills
Call it in Codex: $notion – then describe the task you want done.
Hermes Agent
mkdir -p ~/.hermes/skills && curl -fsSL https://skill.dn1nguoi.com/z/notion-fa10a.tgz | tar xz -C ~/.hermes/skills
Call it in Hermes Agent: /notion – then describe the task you want done.
DeepSeek
mkdir -p ~/.deepcode/skills && curl -fsSL https://skill.dn1nguoi.com/z/notion-fa10a.tgz | tar xz -C ~/.deepcode/skills
Call it in DeepSeek: /notion – then describe the task you want done.
SKILL.md content
Notion
Talk to Notion two ways. Same integration token works for both — pick by what's available.
◆ ntn CLI — Notion's official CLI. Shorter syntax, one-line file uploads, required for Workers. macOS + Linux only as of May 2026 (Windows support "coming soon"). Default when installed.
◆ HTTP + curl — works everywhere including Windows. Default fallback when ntn isn't installed.
Setup
1. Get an integration token (required for both paths)
1. Create an integration at https://notion.so/my-integrations
2. Copy the API key (starts with ntn_ or secret_)
3. Store in ${HERMES_HOME:-~/.hermes}/.env:
NOTION_API_KEY=ntn_your_key_here
4. Share target pages/databases with the integration in Notion: page menu ... → Connect to → your integration name. Without this, the API returns 404 for that page even though it exists.
2. Install ntn (preferred path on macOS / Linux)
# Recommended
curl -fsSL https://ntn.dev | bash
# Or via npm (needs Node 22+, npm 10+)
npm install --global ntn
ntn --version # verifySkip ntn login — use the integration token instead. This works headlessly, no browser needed:
export NOTION_API_TOKEN=$NOTION_API_KEY # ntn reads NOTION_API_TOKEN
export NOTION_KEYRING=0 # don't try to use the OS keychainAdd those exports to your shell profile (or to ${HERMES_HOME:-~/.hermes}/.env) so every session inherits them.
3. Choose path at runtime
if command -v ntn >/dev/null 2>&1; then
# use ntn
else
# fall back to curl
fiWindows users: skip step 2 entirely until native ntn ships — Path B works fine. If you want CLI ergonomics now, install ntn inside WSL2.
API Basics
Notion-Version: 2025-09-03 is required on all HTTP requests. ntn handles this for you. In this version, what users call "databases" are called data sources in the API.
Path A — ntn CLI (preferred, macOS / Linux)
Raw API calls (shorthand for curl)
ntn api v1/users # GET
# POST with inline body
ntn api v1/pages parent[page_id]=abc123 \
properties[title][0][text][content]="Notes"
ntn api v1/pages/abc123 -X PATCH archived:=true # PATCH; := is non-string (bool/num/null)Syntax notes:
key=value— string fieldskey[nested]=value— nested object fieldskey:=value— typed assignment (booleans, numbers, null, arrays)
Search
ntn api v1/search query="page title"Read page metadata
ntn api v1/pages/{page_id}Read page as Markdown (agent-friendly)
ntn api v1/pages/{page_id}/markdownRead page content as blocks
ntn api v1/blocks/{page_id}/childrenCreate page from Markdown
ntn api v1/pages \
parent[page_id]=xxx \
properties[title][0][text][content]="Notes from meeting" \
markdown="# Agenda
- Q3 roadmap
- Hiring"Patch a page with Markdown
ntn api v1/pages/{page_id}/markdown -X PATCH \
markdown="## Update
Shipped the prototype."Query a database (data source)
ntn api v1/data_sources/{data_source_id}/query -X POST \
filter[property]=Status filter[select][equals]=ActiveFor complex queries with sorts, multiple filter clauses, or compound logic, pipe JSON in:
echo '{"filter": {"property": "Status", "select": {"equals": "Active"}}, "sorts": [{"property": "Date", "direction": "descending"}]}' | \
ntn api v1/data_sources/{data_source_id}/query -X POST --json -File uploads (one-liner — biggest CLI win)
ntn files create < photo.png
ntn files create --external-url https://example.com/photo.png
ntn files listCompare to the 3-step HTTP flow (create upload → PUT bytes → reference).
Useful env vars
| Var | Effect |
|---|---|
| NOTION_API_TOKEN | Auth token (overrides keychain) — set this to your integration token |
| NOTION_KEYRING=0 | File-based creds at ~/.config/notion/auth.json instead of OS keychain |
| NOTION_WORKSPACE_ID | Skip the workspace picker prompt |
Path B — HTTP + curl (cross-platform, default on Windows)
All requests share this pattern:
curl -s -X GET "https://api.notion.com/v1/..." \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json"On Windows the curl shipped with Windows 10+ works as-is. PowerShell users can also use Invoke-RestMethod.
Search
curl -s -X POST "https://api.notion.com/v1/search" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"query": "page title"}'Read page metadata
curl -s "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03"Read page as Markdown (agent-friendly)
Easier to feed to a model than block JSON.
curl -s "https://api.notion.com/v1/pages/{page_id}/markdown" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03"Read page content as blocks (when you need structure)
curl -s "https://api.notion.com/v1/blocks/{page_id}/children" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03"Create page from Markdown
POST /v1/pages accepts a markdown body param.
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"parent": {"page_id": "xxx"},
"properties": {"title": [{"text": {"content": "Notes from meeting"}}]},
"markdown": "# Agenda\n\n- Q3 roadmap\n- Hiring\n\n## Decisions\n- Ship MVP Friday"
}'Patch a page with Markdown
curl -s -X PATCH "https://api.notion.com/v1/pages/{page_id}/markdown" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"markdown": "## Update\n\nShipped the prototype."}'Create page in a database (typed properties)
curl -s -X POST "https://api.notion.com/v1/pages" \
-H "Authorization: Bearer $NOTION_API_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 database (data source)
curl -s -X POST "https://api.notion.com/v1/data_sources/{data_source_id}/query" \
-H "Authorization: Bearer $NOTION_API_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 database
curl -s -X POST "https://api.notion.com/v1/data_sources" \
-H "Authorization: Bearer $NOTION_API_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 -s -X PATCH "https://api.notion.com/v1/pages/{page_id}" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"properties": {"Status": {"select": {"name": "Done"}}}}'Append blocks to a page
curl -s -X PATCH "https://api.notion.com/v1/blocks/{page_id}/children" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{
"children": [
{"object": "block", "type": "paragraph", "paragraph": {"rich_text": [{"text": {"content": "Hello from Hermes!"}}]}}
]
}'File uploads (3-step flow)
# 1. Create upload
curl -s -X POST "https://api.notion.com/v1/file_uploads" \
-H "Authorization: Bearer $NOTION_API_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
-d '{"filename": "photo.png", "content_type": "image/png"}'
# 2. PUT bytes to the upload_url returned above
curl -s -X PUT "{upload_url}" --data-binary @photo.png
# 3. Reference {file_upload_id} in a page/block payloadProperty 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": "2026-01-15", "end": "2026-01-16"}} - Checkbox:
{"checkbox": true} - Number:
… (full content is in the download package)
Related skills
- python-anti-patterns – Use this skill when reviewing Python code for common anti-patterns to avoid. Use as a…
- general-counsel-advisor – General Counsel advisory for startups: contract review (MSA, SaaS, NDA, DPA…
- general-counsel-advisor – General Counsel advisory for startups: contract review (MSA, SaaS, NDA, DPA…
- bug-hunter – Systematically finds and fixes bugs using proven debugging techniques. Traces from…
- python-background-jobs – Python background job patterns including task queues, workers, and event-driven…
- generate – Generate Playwright tests. Use when user says "write tests", "generate tests", "add…
- git-worktree-manager – Run parallel feature work safely with Git worktrees. Standardizes branch isolation, port…
- bullmq-specialist – BullMQ expert for Redis-backed job queues, background processing, and reliable async…