Transform complex Notion API interactions into simple, Pythonic code. Perfect for developers building AI agents, automation workflows, and dynamic content systems.
Why Notionary?
AI-friendly
Composable APIs that drop cleanly into agent workflows
Smart discovery
Find pages/databases by title with fuzzy matching — no ID spelunking
Markdown content
Read & write page content as Markdown via the Notion Markdown API
Async-first
Modern Python with full async / await
Round-trip editing
Read a page as Markdown, transform it, write it back
Full coverage
Pages, databases, data sources, file uploads, users, workspace search
Installation
pip install notionary
Set your Notion integration token:
export NOTION_API_KEY=your_integration_key
Quick Start
All access goes through the Notionary client, which exposes namespace objects — each mapping to a Notion API area.
import asyncio
from notionary import Notionary
asyncdefmain():
asyncwith Notionary() as notion:
# Find a page by title (fuzzy matching)
page = await notion.pages.find("Meeting Notes")
print(page.title, page.url)
# Read content as Markdown
md = await page.get_markdown()
print(md)
# Append contentawait page.append("## Action Items\n- [ ] Review proposal")
# Replace all contentawait page.replace("# Fresh Start\nThis page was rewritten.")
asyncio.run(main())
For relation properties on data-source pages, you can pass a page ID (UUID string) or a page title — the title is automatically resolved to an ID:
# By page IDawait page.set_property("Project", "abc123...")
# By title (auto-resolved via the related data source)await page.set_property("Project", "Quarterly Review")
from pathlib import Path
asyncwith Notionary() as notion:
# Upload from disk
result = await notion.file_uploads.upload(Path("./report.pdf"))
# Upload from bytes (e.g. generated images, in-memory content)
result = await notion.file_uploads.upload_from_bytes(
content=image_bytes,
filename="chart.png",
)
# List previous uploads
uploads = await notion.file_uploads.list()
Users
asyncwith Notionary() as notion:
all_users = await notion.users.list()
people = await notion.users.list(filter="person")
bots = await notion.users.list(filter="bot")
me = await notion.users.me()
matches = await notion.users.search("alex")
Workspace Search
asyncwith Notionary() as notion:
results = await notion.workspace.search(query="roadmap")
for r in results:
print(type(r).__name__, r.title)
Key Features
Smart Discovery
Find pages and databases by human-readable name
Fuzzy matching handles typos and partial titles
No more hunting for opaque IDs or copying page URLs
Works with LangChain, LlamaIndex, OpenAI Agents SDK, Claude, and custom agent runtimes
Contributing
Contributions are welcome — whether you're fixing bugs, adding features, improving docs, or sharing examples.
Check the Contributing Guide to get started.
Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support
We found that notionary demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago.It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.