Skip to main content

Python library for programmatic Notion workspace management - databases, pages, and content with advanced Markdown support

Project description

Notionary logo

Notionary

PyPI version Python Version License: MIT Downloads Documentation Notion API

The Modern Notion API for Python & AI Agents

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

async def main():
    async with 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 content
        await page.append("## Action Items\n- [ ] Review proposal")

        # Replace all content
        await page.replace("# Fresh Start\nThis page was rewritten.")

asyncio.run(main())

Core API

Pages

async with Notionary() as notion:
    # Lookup
    page = await notion.pages.find("Sprint Board")
    page = await notion.pages.from_id(page_uuid)

    # List & search
    pages = await notion.pages.list(query="roadmap")

Content (Markdown API)

    md = await page.get_markdown()       # read as Markdown
    await page.append("## New Section") # append blocks
    await page.replace("# Replaced")   # overwrite all content
    await page.clear()                  # remove all blocks

Metadata

    await page.rename("New Title")
    await page.set_icon("🚀")
    await page.set_cover("https://example.com/cover.png")
    await page.random_cover()

Properties

    # Set a single property (type-validated against the schema)
    await page.set_property("Status", "Done")
    await page.set_property("Due Date", "2025-12-31")
    await page.set_property("Priority", 3)
    await page.set_property("Archived", True)
    await page.set_property("Tags", ["backend", "urgent"])

    # Set multiple properties in one API call
    await page.set_properties({
        "Status": "In Progress",
        "Due Date": "2025-12-31",
        "Priority": 2,
    })

    # Inspect the property schema (types, current values, valid options)
    schema = await page.describe_properties()
    # schema["Status"] → PagePropertyDescription(type="status", current="Todo", options=["Todo", "In Progress", "Done"])

Supported property types: checkbox, date, email, multi_select, number, phone_number, rich_text, select, status, title, url, relation.

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 ID
    await page.set_property("Project", "abc123...")
    # By title (auto-resolved via the related data source)
    await page.set_property("Project", "Quarterly Review")

Comments & Lifecycle

    await page.comment("Review completed")
    await page.lock()
    await page.trash()

Notion API Reference: Pages · Markdown


Databases

async with Notionary() as notion:
    # Lookup
    db = await notion.databases.find("Tasks")
    db = await notion.databases.from_id(db_uuid)

    # Create
    db = await notion.databases.create(
        parent_page_id=page_uuid,
        title="New Database",
        icon_emoji="📊",
    )

    # Metadata
    await db.set_title("Project Tracker")
    await db.set_description("All current projects")
    await db.set_icon("📊")
    await db.lock()

Notion API Reference: Databases


Data Sources

Data sources represent queryable Notion databases with schema awareness — useful for building structured content pipelines.

async with Notionary() as notion:
    ds = await notion.data_sources.find("Engineering Backlog")

    # Schema introspection — property types, current options, and relation pages
    schema = await ds.describe_properties()
    # schema["Status"] → DataSourcePropertyDescription(type="status", options=["Todo", "In Progress", "Done"])
    # schema["Assignee"] → DataSourcePropertyDescription(type="relation", relation_options=[...])

    # Create a page inside the data source
    page = await ds.create_page(title="New Feature")

    # Query with filters
    results = await ds.query(filter={"property": "Status", "select": {"equals": "In Progress"}})

    # Metadata
    await ds.set_title("Sprint Board")
    await ds.set_icon("🧭")

Notion API Reference: Data Sources


File Uploads

from pathlib import Path

async with 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

async with 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

async with 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

Markdown Content API

  • Read any Notion page as clean Markdown
  • Append or replace blocks using Markdown syntax
  • Powered by the official Notion Markdown API

Round-Trip Editing

# Read → transform → write back
md = await page.get_markdown()
updated = md.replace("Draft", "Final")
await page.replace(updated)

Modern Python

  • Full async / await support throughout
  • Type hints on all public APIs
  • Pydantic models for all API responses
  • Context-manager client for clean resource handling

AI-Ready Architecture

  • Namespace-based API maps naturally to agent tool sets
  • Predictable response models enable prompt chaining
  • 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.


Documentation

mathisarends.github.io/notionary — Complete API reference auto-generated from source.


Built with ❤️ for Python developers and AI agents

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

notionary-0.7.0.tar.gz (17.8 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

notionary-0.7.0-py3-none-any.whl (84.1 kB view details)

Uploaded Python 3

File details

Details for the file notionary-0.7.0.tar.gz.

File metadata

  • Download URL: notionary-0.7.0.tar.gz
  • Upload date:
  • Size: 17.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for notionary-0.7.0.tar.gz
Algorithm Hash digest
SHA256 1615c67ddd8641bde3e0c812861f377d5168c7b34815921b437cfdc378415ade
MD5 23920f43c07b2c8f7b6d5f20e3438b4e
BLAKE2b-256 60d8953f3699eee599eff64b97083cc1e11f62e1cb4f9f8ad5142478f84803df

See more details on using hashes here.

File details

Details for the file notionary-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: notionary-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 84.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.2

File hashes

Hashes for notionary-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a223b8d4cca99c43a108108ad13bc5ef1f1205b37bbdcb8daac01b8dbf3ee841
MD5 e4afb83abc0fb46de10988ef61b58406
BLAKE2b-256 856af5a9824f815439cb2d5f8a22ba0ec7bc48911b66e0da74a3d7891d9e499a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page