Notion
Notion page and database CRUD via API — create, read, update, and query Notion pages, data sources (databases), and blocks directly from CLI-JAW using the Notion API.
Quick Reference
| Skill name | notion |
| Status | Active (auto-injected into every session) |
| Category | Productivity |
| SKILL.md path | ~/.cli-jaw/skills/notion/SKILL.md |
| Homepage | developers.notion.com |
| API version | 2025-09-03 (latest) |
| Requires | NOTION_API_KEY environment variable (key with ntn_ prefix) |
| Key location | ~/.config/notion/api_key |
| OAuth config | ~/.config/notion/oauth.env |
| Rate limit | ~3 requests/sec (use time.sleep(0.35) for batch operations) |
| Install | Pre-installed (ships with CLI-JAW) |
Overview
The notion skill provides full CRUD access to Notion workspaces through the Notion API. It enables CLI-JAW to search for pages, create and update content, query databases (data sources), manage blocks, and apply visual design patterns — all without leaving the terminal.
Key capabilities:
- Search — find pages and data sources by title or content
- Read — retrieve page properties and block-level content
- Create — add new pages to workspaces or data sources, create new data sources
- Update — modify page properties, append blocks, change status fields
- Query — filter and sort data source entries with structured queries
- Design — apply Notion-native visual patterns (mentions, callouts, icons)
Setup
Before using the Notion skill, you need an API integration key and the correct permissions.
| Step | Action |
|---|---|
| 1. Create integration | Go to notion.so/my-integrations and create a new internal integration |
| 2. Copy the API key | The key starts with ntn_ |
| 3. Store the key | Save to ~/.config/notion/api_key |
| 4. Share pages | In Notion, share each target page/database with your integration |
# Store your API key
mkdir -p ~/.config/notion
echo "ntn_your_api_key_here" > ~/.config/notion/api_key
chmod 600 ~/.config/notion/api_key
API Helper Function
The skill defines a reusable shell helper that all operations are built on. CLI-JAW uses this internally when executing Notion commands:
NOTION_KEY=$(cat ~/.config/notion/api_key)
# Helper function used by all API calls
notion_api() {
local method=$1 endpoint=$2 data=$3
curl -s -X "$method" "https://api.notion.com/v1$endpoint" \
-H "Authorization: Bearer $NOTION_KEY" \
-H "Notion-Version: 2025-09-03" \
-H "Content-Type: application/json" \
${data:+-d "$data"}
}
Common Operations
Search
Find pages and data sources by title. Returns matching objects with their IDs.
# Search for pages by title
notion_api POST /search '{"query": "page title"}'
# Discover workspace page IDs
notion_api POST /search '{"query": "Meeting Notes"}'
Read Pages and Blocks
Retrieve page properties and their block-level content.
# Get page properties
notion_api GET /pages/{page_id}
# Get page content (all child blocks)
notion_api GET /blocks/{page_id}/children
Create Pages
Create a new page inside a data source (database) with properties, or as a child of an existing page.
# Create a page in a data source
notion_api POST /pages '{
"parent": {"database_id": "xxx"},
"properties": {
"Name": {"title": [{"text": {"content": "New Item"}}]},
"Status": {"select": {"name": "Todo"}}
}
}'
Update Pages
Modify page properties without affecting the page content (blocks).
# Update a status property
notion_api PATCH /pages/{page_id} \
'{"properties": {"Status": {"select": {"name": "Done"}}}}'
Append Blocks
Add new content blocks to an existing page.
# Add a paragraph block
notion_api PATCH /blocks/{page_id}/children '{
"children": [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [{"text": {"content": "Hello, world!"}}]
}
}
]
}'
Query Data Sources
Filter and sort database entries with structured queries.
# Query with filter and sort
notion_api POST /data_sources/{data_source_id}/query '{
"filter": {
"property": "Status",
"select": {"equals": "Active"}
},
"sorts": [
{"property": "Date", "direction": "descending"}
]
}'
Create Data Sources
Create a new database (data source) with a defined schema.
# Create a new data source with properties
notion_api POST /data_sources '{
"parent": {"page_id": "xxx"},
"title": [{"text": {"content": "My Database"}}],
"properties": {
"Name": {"title": {}},
"Status": {"select": {"options": [{"name": "Todo"}, {"name": "Done"}]}},
"Date": {"date": {}}
}
}'
Property Types Reference
Each property type has a specific JSON structure. Use the correct format when creating or updating page properties.
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": "2024-01-15", "end": "2024-01-16"}}
Checkbox
{"checkbox": true}
Number
{"number": 42}
URL
{"url": "https://..."}
{"email": "user@example.com"}
Relation
{"relation": [{"id": "page_id"}]}
2025-09-03 API Changes
The latest Notion API version introduces significant changes to how databases are handled. The skill is built on this version.
/data_sources/ endpoints for queries. The term "database" is replaced by "data source" in the API.
database_id is used for creating pages inside a database, while data_source_id is used for querying. Both are present in API responses.
"object": "data_source" instead of "object": "database".
parent.data_source_id and parent.database_id when the parent is a database.
database_id for POST /pages (creating entries) and data_source_id for POST /data_sources/{id}/query (querying entries). Mixing them up will cause 404 errors.Visual Design Rules
The skill includes a set of visual design rules (referred to as the "aesthetics guide") that ensure Notion pages created by CLI-JAW look polished and follow Notion-native patterns.
1. Use mention links for page references
Mention links create automatic backlinks and display the referenced page's icon. Always prefer mentions over plain-text page names.
// Correct: mention link (creates backlink, shows icon)
{"type": "mention", "mention": {"type": "page", "page": {"id": "page-UUID"}}}
// Incorrect: plain text (no backlink, no icon)
{"type": "text", "text": {"content": "Page Name"}}
2. Skip emoji in text when using mentions
Mentions automatically display the page's icon. Adding emoji text alongside a mention creates visual duplication. Let the mention handle the icon.
3. Use callout + mention for navigation hubs
For pages that serve as hubs or dashboards, use a callout block with mention links separated by a dot separator for clean navigation.
{"object": "block", "type": "callout", "callout": {
"rich_text": [
{"type": "mention", "mention": {"type": "page", "page": {"id": "dashboard-UUID"}}},
{"type": "text", "text": {"content": " · "}},
{"type": "mention", "mention": {"type": "page", "page": {"id": "operations-UUID"}}}
],
"icon": {"type": "emoji", "emoji": "🏠"},
"color": "gray_background"
}}
4. Preserve child_page blocks
Deleting a child_page block permanently archives its subpage. When clearing or rebuilding page content, always filter out child_page blocks before deletion.
# Python: safely clear blocks without archiving subpages
for block in children:
if block["type"] != "child_page":
delete_block(block["id"])
5. Standard page structure pattern
Follow this layout for well-structured Notion pages:
divider
heading_2 (section title)
callout (mention links) + gray_background ← navigation
divider
heading_2 (Quick Links)
bulleted_list_item (mention → description)
6. Icons and covers
Set a meaningful emoji icon on every page. For key pages (dashboards, project hubs), add an Unsplash cover image at w=1500 resolution for visual polish.
7. Mention caveats
- Archived pages render mentions as plain text (no icon, no link)
- The integration must have access to the target page for mentions to resolve
- Rate limit: ~3 requests/sec — use
time.sleep(0.35)in batch operations to avoid throttling
Environment and Configuration
| File | Purpose |
|---|---|
~/.config/notion/api_key | Primary API key storage (also checked as access_token) |
~/.config/notion/oauth.env | OAuth configuration for public integrations |
NOTION_API_KEY env var | Environment variable override (takes precedence) |
To discover workspace page IDs for use in scripts and commands:
# Search by name to find page/database UUIDs
notion_api POST /search '{"query": "page name"}'
Usage Examples (~해줌)
Real-world usage patterns in the natural Korean style that CLI-JAW understands.
POST /pages with the correct property types.POST /data_sources/{id}/query with a filter on the Status select property equaling "Todo", sorted by date descending. Returns all matching entries.GET /blocks/{page_id}/children, reads all block content recursively, and generates a summary. Handles nested blocks like toggles and callouts.POST /data_sources with three properties: a title property for Name, a select property with "Todo" and "Done" options for Status, and a date property. Sets the parent to the specified page.Important Notes
- Page/database IDs are UUIDs — dashes are optional (
abc123def456andabc123-def4-56...both work) - Database view filters are UI-only and cannot be set or read via the API
- Inline data sources: use
is_inline: truewhen creating a data source to embed it inside a page rather than as a standalone full-page database - child_page safety: never delete
child_pageblocks when clearing content — this permanently archives the subpage - Dual ID system: in the 2025-09-03 API, databases have both
database_id(for page creation) anddata_source_id(for queries) — use the correct one for each operation - Rate limiting: the Notion API allows ~3 requests/sec; insert
time.sleep(0.35)between calls in batch scripts - Integration access: every page and database you want to access must be explicitly shared with the integration in Notion's share dialog
Related
- Notion API Documentation — official Notion API reference
- Productivity Skills — category page for Notion and related productivity skills
- Memory — persistent knowledge storage across sessions
- Skill Catalog — browse all skills
- CLI Commands — full CLI-JAW command reference