Skip to content
Learn Agentic AI10 min read0 views

Integrating AI Agents with Notion: Automatic Page Creation and Database Updates

Connect your AI agent to Notion for automatic page creation, database row updates, and block-level content manipulation using the Notion API, with practical Python examples for common automation patterns.

Why Connect AI Agents to Notion

Notion serves as a knowledge hub for many teams — meeting notes, project documentation, task databases, and wikis all live there. An AI agent with Notion access can automatically create meeting summaries, update project statuses, generate documentation from code changes, and maintain knowledge bases without manual data entry.

The Notion API provides comprehensive access to pages, databases, and blocks, making it an ideal target for AI agent write-back operations.

Setting Up the Notion Client

Create an integration at notion.so/my-integrations, then share the relevant Notion pages or databases with your integration. The integration token grants access only to explicitly shared content.

import httpx
from typing import Any

class NotionClient:
    BASE_URL = "https://api.notion.com/v1"

    def __init__(self, token: str):
        self.headers = {
            "Authorization": f"Bearer {token}",
            "Notion-Version": "2022-06-28",
            "Content-Type": "application/json",
        }
        self.http = httpx.AsyncClient(
            base_url=self.BASE_URL,
            headers=self.headers,
            timeout=30.0,
        )

    async def create_page(self, parent_id: str, properties: dict,
                          children: list = None) -> dict:
        payload = {
            "parent": {"database_id": parent_id},
            "properties": properties,
        }
        if children:
            payload["children"] = children

        response = await self.http.post("/pages", json=payload)
        response.raise_for_status()
        return response.json()

    async def query_database(self, database_id: str,
                             filter_obj: dict = None,
                             sorts: list = None) -> list[dict]:
        payload = {}
        if filter_obj:
            payload["filter"] = filter_obj
        if sorts:
            payload["sorts"] = sorts

        response = await self.http.post(
            f"/databases/{database_id}/query", json=payload
        )
        response.raise_for_status()
        return response.json()["results"]

Creating Pages from AI Agent Output

When your agent generates structured output — like a meeting summary or research report — write it directly into Notion as a formatted page.

async def create_meeting_summary(
    notion: NotionClient,
    database_id: str,
    agent_output: dict,
):
    properties = {
        "Name": {
            "title": [{"text": {"content": agent_output["title"]}}]
        },
        "Date": {
            "date": {"start": agent_output["date"]}
        },
        "Status": {
            "select": {"name": "Completed"}
        },
        "Tags": {
            "multi_select": [
                {"name": tag} for tag in agent_output["tags"]
            ]
        },
    }

    children = [
        {
            "object": "block",
            "type": "heading_2",
            "heading_2": {
                "rich_text": [{"text": {"content": "Summary"}}]
            },
        },
        {
            "object": "block",
            "type": "paragraph",
            "paragraph": {
                "rich_text": [{"text": {"content": agent_output["summary"]}}]
            },
        },
        {
            "object": "block",
            "type": "heading_2",
            "heading_2": {
                "rich_text": [{"text": {"content": "Action Items"}}]
            },
        },
    ]

    for item in agent_output["action_items"]:
        children.append({
            "object": "block",
            "type": "to_do",
            "to_do": {
                "rich_text": [{"text": {"content": item}}],
                "checked": False,
            },
        })

    page = await notion.create_page(database_id, properties, children)
    return page["id"]

Querying and Updating Database Rows

AI agents often need to read existing data, reason about it, then update records. The query API supports rich filtering.

See AI Voice Agents Handle Real Calls

Book a free demo or calculate how much you can save with AI voice automation.

async def update_stale_tasks(notion: NotionClient, database_id: str):
    # Find tasks that are overdue and still in progress
    stale_tasks = await notion.query_database(
        database_id,
        filter_obj={
            "and": [
                {
                    "property": "Status",
                    "select": {"equals": "In Progress"},
                },
                {
                    "property": "Due Date",
                    "date": {"before": "2026-03-17"},
                },
            ]
        },
    )

    for task in stale_tasks:
        task_id = task["id"]
        task_name = task["properties"]["Name"]["title"][0]["text"]["content"]

        # Let the agent decide what to do with each stale task
        decision = await agent.run(
            prompt=f"Task '{task_name}' is overdue. Should we escalate, "
                   f"extend the deadline, or mark as blocked?"
        )

        await notion.http.patch(
            f"/pages/{task_id}",
            json={
                "properties": {
                    "Status": {"select": {"name": decision.new_status}},
                    "Notes": {
                        "rich_text": [
                            {"text": {"content": decision.reason}}
                        ]
                    },
                }
            },
        )

Appending Blocks to Existing Pages

Sometimes you need to add content to an existing page rather than creating a new one — for example, appending daily logs to a running document.

async def append_to_page(
    notion: NotionClient,
    page_id: str,
    content_blocks: list[dict],
):
    response = await notion.http.patch(
        f"/blocks/{page_id}/children",
        json={"children": content_blocks},
    )
    response.raise_for_status()
    return response.json()

# Usage: append agent's daily digest
async def write_daily_digest(notion, page_id, agent_summary):
    blocks = [
        {
            "type": "heading_3",
            "heading_3": {
                "rich_text": [{"text": {"content": f"Digest for 2026-03-17"}}]
            },
        },
        {
            "type": "paragraph",
            "paragraph": {
                "rich_text": [{"text": {"content": agent_summary}}]
            },
        },
        {"type": "divider", "divider": {}},
    ]
    await append_to_page(notion, page_id, blocks)

FAQ

What are the Notion API rate limits and how should I handle them?

The Notion API allows 3 requests per second per integration. Implement exponential backoff when you receive 429 status codes. For batch operations, use asyncio.Semaphore to throttle concurrent requests and add a small delay between calls to stay well under the limit.

Can I create Notion pages with embedded images or files?

Yes. Use the image block type with an external URL, or the file block type. However, the Notion API does not support uploading files directly — you must host images externally (S3, Cloudflare R2) and reference them by URL in your block definitions.

How do I handle Notion's block nesting limits?

Notion supports up to 2 levels of block nesting via the API. If your AI agent generates deeply nested content (like nested bullet lists), flatten the structure or use indentation-style formatting. You can append children to a block after creation using the append block children endpoint.


#Notion #NotionAPI #KnowledgeManagement #AIAgents #Automation #AgenticAI #LearnAI #AIEngineering

Share this article
C

CallSphere Team

Expert insights on AI voice agents and customer communication automation.

Try CallSphere AI Voice Agents

See how AI voice agents work for your industry. Live demo available -- no signup required.