---
name: avizmarlon/notion-batch-pattern
source: https://app.decimal.ai/s/avizmarlon-notion-batch-pattern@1/SKILL.md
source_sha256: 957cd3fee693
---

## When to use Notion API vs. MCP

**Notion API (REST) is mandatory for batch operations; MCP (Model Context Protocol) is for single-page CRUD only.**

### The problem with MCP for batch work

Most Notion MCP implementations have critical limitations for scaled operations:

- **Hard cap on results**: semantic search limited to ~25 results per query with no pagination mechanism
- **No full database scan**: cannot iterate over all rows in a database reliably
- **Whack-a-mole pattern**: multiple sequential queries required to retrieve complete data, leading to repeated context loading and inefficient execution
- **No file uploads**: many MCP versions do not support file upload operations

**Real-world impact**: A task requiring batch standardization of 65+ rows may take 4+ separate API calls via MCP (each capped at 25 results, no pagination), whereas the same task via Notion REST API with proper pagination completes in a single pass.

### Decision tree

| Operation | Recommended Tool | Why |
|-----------|---|---|
| Create 1 page, read 1 page, update single entry, inline comment/annotation | MCP | Simpler setup, no auth management overhead |
| Query entire database, batch update (≥3 rows), full scan/inventory, any operation requiring pagination | **Notion REST API** | Full pagination support, no result caps, complete control |
| File upload (bulk or single) | **Notion REST API** | MCP rarely supports this; REST API has official file upload endpoints |
| Database creation or replication of page structure | **Notion REST API** | Programmatic structure building requires full API control |

## Using Notion REST API

### Prerequisites

1. **Notion API Token** — create at https://www.notion.com/my-integrations and grant permissions to databases/pages you need.
2. **Store securely** — save the token in environment variables (e.g., `NOTION_TOKEN`) or a credential vault; never hardcode.
3. **Pagination awareness** — Notion returns max 100 items per request; use `start_cursor` and `next_cursor` for full retrieval.

### Implementation pattern

The Notion REST API covers pages (CRUD), databases (query with pagination), blocks (children enumeration), users, and comments. Rate limits are typically 3 requests/second; include backoff for 429 responses. Check the official API reference for the current version.

**Example: Query a database with pagination**

```python
import os
import requests

NOTION_TOKEN = os.environ.get("NOTION_TOKEN")
DATABASE_ID = "your-database-id"

headers = {
    "Authorization": f"Bearer {NOTION_TOKEN}",
    "Notion-Version": "2024-06-15"
}

def query_db_paginated(db_id):
    """Retrieve all pages from a Notion database with automatic pagination."""
    all_pages = []
    start_cursor = None
    
    while True:
        payload = {}
        if start_cursor:
            payload["start_cursor"] = start_cursor
        
        response = requests.post(
            f"https://api.notion.com/v1/databases/{db_id}/query",
            headers=headers,
            json=payload
        )
        response.raise_for_status()
        data = response.json()
        
        all_pages.extend(data["results"])
        
        if not data.get("has_more"):
            break
        start_cursor = data.get("next_cursor")
    
    return all_pages

# Fetch and process
pages = query_db_paginated(DATABASE_ID)
for page in pages:
    title = page["properties"]["Name"]["title"][0]["plain_text"]
    print(f"Page: {title}")
```

### Building abstractions

For repeated operations, create helper functions:

- **Property builders**: encapsulate property object construction (`title`, `select`, `date`, `relation`, etc.)
- **Block builders**: standardize common blocks (`paragraph`, `heading`, `code`, etc.)
- **Auto-pagination wrappers**: handle cursor management transparently
- **Error handling**: implement backoff for rate limits (429), transient errors (5xx), and validation errors (400)

Example helper:
```python
def update_page_property(page_id, property_name, property_value):
    """Update a single property on a Notion page with error handling."""
    payload = {
        "properties": {
            property_name: property_value
        }
    }
    
    response = requests.patch(
        f"https://api.notion.com/v1/pages/{page_id}",
        headers=headers,
        json=payload
    )
    
    if response.status_code == 429:
        # Rate limited; back off and retry
        raise Exception("Rate limited — implement exponential backoff")
    
    response.raise_for_status()
    return response.json()
```

## Anti-patterns to avoid

- **Using semantic search MCP for exhaustive queries**: Semantic MCP always returns capped results. Use REST API database query with filters instead.
- **Hand-rolling pagination instead of using official SDKs/wrappers**: If your team/org has a Notion wrapper library, use it; reinventing auth + cursor management introduces bugs.
- **Treating MCP as a complete Notion client**: It's a convenience tool for simple read-write, not a replacement for the full API when scale matters.
- **Ignoring rate limits**: Notion enforces 3 requests/second per integration. Batch operations without backoff will fail; include exponential backoff by default.
- **Assuming all properties/blocks are created equal**: Some property types (rich text, rollups, formulas) require specific payload structures; consult Notion's API reference.

## Notion API reference

- **Official docs**: https://developers.notion.com/reference/intro
- **Latest API version**: 2024-06 (check for updates when upgrading)
- **Common endpoints**:
  - `POST /v1/databases/{database_id}/query` — database query with filters and sorts
  - `GET /v1/databases/{database_id}` — fetch database schema
  - `PATCH /v1/pages/{page_id}` — update page properties
  - `POST /v1/pages/{page_id}/children` — append blocks to a page
  - `GET /v1/blocks/{block_id}/children` — fetch children of a block with pagination

## Why this matters for AI agents

When an AI agent is tasked with Notion data work:

1. **Single operation ≠ batch**: The agent should auto-detect when a task crosses the ≥3-row threshold and proactively propose REST API instead of MCP.
2. **Pagination is non-optional**: Declaring "found all rows" without checking `has_more: false` or consuming all cursors is a common failure mode.
3. **Deterministic structure**: The REST API response structure is stable and fully documented; the agent can build confident parsers and helpers.
4. **Scalability**: As task scope grows (backlog sync, portfolio updates, data migrations), the API scales without architectural rework.

This decision pattern applies universally to AI agents working with Notion at scale, not just a single operator's workflow.