A high-level Python SDK for the Notion API with developer experience in mind.
Project description
Better Notion
A pythonic, object-oriented SDK for the Notion API.
🚀 Quick Start
pip install better-notion
import asyncio
from better_notion import NotionAPI
async def main():
async with NotionAPI(auth="secret_...") as api:
# Get a page
page = await api.pages.get("page_id")
print(page.properties)
# List pages in a database
async for page in api.pages.iterate("database_id"):
print(page.title)
asyncio.run(main())
✨ Why Better Notion?
- 🎯 Object-Oriented: Work with entities, not JSON dicts
- 🔋 Type-Safe: Property builders for compile-time safety
- 📄 Paginated: Automatic cursor-based pagination
- 🔍 Powerful Search: Search across your entire workspace
- ⚡ Async-First: Built with
asyncioandhttpxfor performance
📦 Installation
SDK Installation
# With pip
pip install better-notion
# With uv
uv pip install better-notion
CLI Installation
# Install with CLI support
pip install better-notion[cli]
# Or install everything
pip install better-notion[all]
The CLI provides a notion command for interacting with Notion from the terminal, designed primarily for AI agents.
CLI Status: ⚠️ Experimental - Under active development
💻 CLI Usage
The Better Notion CLI provides a command-line interface for interacting with Notion.
Installation
pip install better-notion[cli]
Basic Commands
# Show version
notion --version
# Check authentication status
notion auth status
# Show help
notion --help
Response Format
All CLI commands return JSON for programmatic parsing:
{
"success": true,
"data": {
"id": "page_123",
"title": "My Page"
},
"meta": {
"version": "0.4.0",
"timestamp": "2025-01-26T10:00:00Z",
"rate_limit": {
"remaining": 48,
"reset_at": "2025-01-26T10:01:00Z"
}
}
}
Error Handling
Errors are returned with structured codes:
{
"success": false,
"error": {
"code": "NOT_FOUND",
"message": "Page not found",
"retry": false
},
"meta": {...}
}
Exit Codes
0- Success1- Generic error2- Invalid input3- Authentication error4- Rate limit exceeded5- Not found6- Conflict
Note: The CLI is currently in experimental stage. See CLI Documentation for more details.
🔑 Authentication
Create an integration at notion.so/my-integrations to get your API token.
from better_notion import NotionAPI
api = NotionAPI(auth="secret_...")
📚 Features
Entities
All Notion objects are represented as Python entities:
- Pages - Create, read, update, delete, archive
- Blocks - Manipulate content blocks
- Databases - Query and manage databases
- Users - Retrieve user information
Property Builders
Type-safe builders for all Notion property types:
from better_notion._api.properties import Title, Select, Date, Checkbox
properties = {
**Title("My Page").build(),
**Select("Status", "In Progress").build(),
**Date("Due Date", "2025-01-15").build(),
**Checkbox("Done", False).build(),
}
Automatic Pagination
Memory-efficient iteration over large datasets:
async for page in api.pages.iterate("database_id"):
# Processes pages lazily, not all at once
process(page)
💡 Usage Examples
Creating a Page
from better_notion import NotionAPI
from better_notion._api.properties import Title, Text
async def create_page():
async with NotionAPI(auth="secret_...") as api:
page = await api.pages.create(
parent={"database_id": "database_id"},
properties={
**Title("My New Page").build(),
**Text("Notes", "Some notes").build(),
}
)
print(f"Created page: {page.id}")
Updating a Page
from better_notion._api.properties import Select
async def update_page():
async with NotionAPI(auth="secret_...") as api:
page = await api.pages.get("page_id")
# Update properties locally
await page.update(
**Select("Status", "Done").build()
)
# Save changes to Notion
await page.save()
Working with Blocks
async def manipulate_blocks():
async with NotionAPI(auth="secret_...") as api:
page = await api.pages.get("page_id")
# Get children blocks
children = await page.blocks.children()
# Append a new block
await page.blocks.append(children=[
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [{"type": "text", "text": {"content": "New paragraph"}}]
}
}
])
Searching
async def search_pages():
async with NotionAPI(auth="secret_...") as api:
# Search for pages matching query
async for result in api.search_iterate("my query"):
if result["object"] == "page":
print(result["properties"]["title"])
📖 API Reference
NotionAPI
The main client for interacting with Notion.
Methods:
search(query, *, filter, sort)- Search pages and blockssearch_iterate(query, *, filter, sort)- Iterate over search results
Collections:
api.pages- PageCollectionapi.blocks- BlockCollectionapi.databases- DatabaseCollectionapi.users- UserCollection
Page
Properties:
id- Page IDcreated_time- Creation datetimelast_edited_time- Last edited datetimearchived- Whether page is archivedproperties- Page properties dictblocks- BlockCollection for children
Methods:
await save()- Save changes to Notionawait delete()- Archive pageawait reload()- Reload from Notionawait update(**kwargs)- Update properties locally
Block
Properties:
id- Block IDtype- Block type (paragraph, heading, etc.)content- Block content
Methods:
await save()- Save changes to Notionawait delete()- Delete blockawait reload()- Reload from Notion
Collections
PageCollection
await get(page_id)- Retrieve a pageawait create(**kwargs)- Create a new pageawait list(database_id, **kwargs)- List pages (first page)iterate(database_id, **kwargs)- Iterate over all pages
BlockCollection
await get(block_id)- Retrieve a blockawait children()- Get children blocksawait append(**kwargs)- Append new blocks
DatabaseCollection
await get(database_id)- Retrieve a databaseawait query(database_id, **kwargs)- Query a databaseawait create_page(database_id, **kwargs)- Create a page in database
UserCollection
await get(user_id)- Retrieve a userawait list()- List all usersawait me()- Get current bot user
🤝 Contributing
Contributions are welcome! Please see CONTRIBUTING.md for details.
Development
# Clone the repository
git clone https://github.com/nesalia-inc/better-notion.git
# Install with dev dependencies
uv sync
# Run tests
uv run pytest
# Run with coverage
uv run pytest --cov=better_notion
📝 License
This project is licensed under the MIT License - see the LICENSE file for details.
🔗 Links
🙏 Acknowledgments
Built with ❤️ using:
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file better_notion-2.8.10.tar.gz.
File metadata
- Download URL: better_notion-2.8.10.tar.gz
- Upload date:
- Size: 282.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
afdfd9d50f69b7818890fccadda421757b4a468fce0a154d5851f778d5a4b3aa
|
|
| MD5 |
505c1cbdad45e5c0ea019d288f665fe8
|
|
| BLAKE2b-256 |
2c8bb33780b620e846226e8db1db5148556bda42cb5dfb2247946267c45346f9
|
File details
Details for the file better_notion-2.8.10-py3-none-any.whl.
File metadata
- Download URL: better_notion-2.8.10-py3-none-any.whl
- Upload date:
- Size: 287.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.26 {"installer":{"name":"uv","version":"0.9.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
393db970b1ba9c7eaf3c7715b8a76337fdcc5c3f62dc017392928c14151a0dd1
|
|
| MD5 |
3ddd6e78e3995eeba917f982baa047b7
|
|
| BLAKE2b-256 |
9461e135096442c30df4dcf921fd6592fb05538aa1d7fd20541ccb5a6827dbdc
|