Notion
Notion Integration
Notion Adapter Architecture
NotionService → NotionAdapter → Notion API v1
OAuth 2.0
Public Integration
or
Internal Token
secret_...
↓
NotionService
service.py
@service_method
delegates→
NotionAdapter
notion_service.py
httpx · auth · cache
HTTPS→
Notion API v1
api.notion.com/v1
Notion-Version: 2022-06-28
↓ auto-generated
HTTP Routes
CLI Commands
MCP Tools
What & Why
Notion is an all-in-one knowledge base and project management tool. With Octopus you can:
- Create and update pages programmatically — generate meeting notes, reports, or documentation from your workflows
- Query databases with filters and sorts — pull structured project data, task lists, or CRM rows into your agents
- Search across your workspace by title — find pages and databases without knowing their IDs
- Append blocks to existing pages — add content, checklists, or logs to living documents
Auth modes
| Mode | Credential | When to use |
|---|---|---|
| OAuth 2.0 | Obtained via OAuth flow (/v1/oauth/notion/authorize) | Public integrations; multi-tenant |
| Internal Token | secret_... from Notion integration settings | Single-workspace automations; server-side scripts |
The adapter reads the token from the JWT bearer at request time. For OAuth the NotionOAuthService subclass retrieves the stored OAuth access token from the credential store.
Notion Data Model
Notion Block Hierarchy
Workspace → Pages / Databases → Blocks / Properties
Workspace
↓
📄 Page
object: "page"
🗃️ Database
object: "database"
↓
↓
Page contains Blocks
paragraph
heading_1 / heading_2 / heading_3
to_do (checkbox)
bulleted_list_item
numbered_list_item
toggle
quote
callout
code
image / video / file
child_page / child_database
All blocks share: id, type, created_time, last_edited_time
Database contains Page rows
Each row is a
page with typed Properties:title (text)
rich_text
number
select / multi_select
status
date
people
checkbox
url / email / phone
relation / rollup
query_database filters work on property type + operator
query_database filter example
{
"property": "Status",
"status": { "equals": "Done" }
}Simplified format also accepted:
{"property": "Name", "contains": "John"} — auto-normalized by the adapter.Methods Reference
| Method | Description | Key Parameters |
|---|---|---|
list_databases | List all databases the integration can access | page_size |
get_database | Retrieve a database by ID | database_id |
query_database | Query database rows with filters and sorts | database_id, filter, sorts, page_size |
create_database_item | Create a new row (page) in a database | database_id, properties, children |
update_database_item | Update properties of a database row | page_id, properties |
list_pages | Search for pages (alias: search with page filter) | query, page_size |
get_page | Retrieve a page by ID with simplified properties | page_id |
create_page | Create a new page under a parent page or database | parent, properties, children, icon, cover |
update_page | Update page properties, icon, cover, or archive status | page_id, properties, archived |
archive_page | Archive (soft-delete) a page | page_id |
get_blocks | Get child blocks of a page or block | block_id, page_size |
append_blocks | Append block children to a page or block | block_id, children, after |
search | Search pages and databases by title across the workspace | query, page_size |
list_users | List all workspace members | page_size |
get_user | Retrieve a specific user by ID | user_id |
Note on
parent: When creating a page inside a database, use{"database_id": "<id>"}. For a sub-page under another page, use{"page_id": "<id>"}.
Note on
properties: For database rows, properties must match the database schema. Useget_databaseto inspect the schema first. The adapter auto-flattens complex Notion property objects to plain values on read.
CLI Examples
# Search pages and databases by title
constellation notion search --query "Q1 Planning"
# List all databases
constellation notion list-databases
# Get a specific database (inspect schema)
constellation notion get-database --database-id abc123
# Query a database with a status filter
constellation notion query-database \
--database-id abc123 \
--filter '{"property": "Status", "status": {"equals": "Done"}}'
# Query with compound filter (and)
constellation notion query-database \
--database-id abc123 \
--filter '{"and": [{"property": "Status", "status": {"equals": "In Progress"}}, {"property": "Assignee", "people": {"contains": "user-id-here"}}]}'
# Get a page
constellation notion get-page --page-id page123
# Create a page under another page
constellation notion create-page \
--parent-id page123 \
--title "New Meeting Notes" \
--content "Hello Notion"
# Create a database row (page) with properties
constellation notion create-database-item \
--database-id abc123 \
--properties '{"Name": {"title": [{"text": {"content": "Sprint 42 Retro"}}]}, "Status": {"status": {"name": "Not started"}}}'
# Update page properties
constellation notion update-page \
--page-id page123 \
--properties '{"Status": {"status": {"name": "Done"}}}'
# Archive a page
constellation notion archive-page --page-id page123
# Get page content (blocks)
constellation notion get-blocks --block-id page123
# Append blocks to a page
constellation notion append-blocks \
--block-id page123 \
--children '[{"type": "paragraph", "paragraph": {"rich_text": [{"type": "text", "text": {"content": "Added via Octopus"}}]}}]'
# List workspace users
constellation notion list-users
# Get a specific user
constellation notion get-user --user-id user123
HTTP API
# Search workspace via HTTP
curl -X POST https://api.yourdomain.com/notion/search \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"query": "Q1 Planning"}'
# Response
# {
# "results": [
# {"id": "page123", "object": "page", "properties": {"title": {"title": [{"plain_text": "Q1 Planning"}]}}}
# ]
# }
# Query database via HTTP
curl -X POST https://api.yourdomain.com/notion/query-database \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"database_id": "abc123", "filter": {"property": "Status", "status": {"equals": "Done"}}}'
# Append blocks via HTTP
curl -X POST https://api.yourdomain.com/notion/append-blocks \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"block_id": "page123",
"children": [{"type": "paragraph", "paragraph": {"rich_text": [{"type": "text", "text": {"content": "Added via Octopus"}}]}}]
}'
Notes
Notion-Versionheader: The adapter pins2022-06-28for public docs compatibility. The internal adapter uses2025-09-03for template support.- Pagination: All list methods use Notion's cursor-based pagination automatically. Pass
page_size(max 100) to control batch size. - Response trimming: All methods return simplified objects by default (plain property values, not raw Notion rich-text arrays). Pass
--rawin CLI orraw=Truein service calls to get full Notion objects. - Block validation:
append_blocksvalidates block structure before sending to the API — helpful error messages indicate which block index is malformed and what the expected structure is. - Filter normalization: Simplified filter format
{"property": "Name", "contains": "John"}is automatically converted to the full Notion format by the adapter.