# Bulk Page Inserts — Large Datasets into Notion

When pushing large structured data (e.g., publication lists, log tables, research corpora) into a Notion page, the 100-block-per-request limit requires batching. This is the Hermes-tested pattern.

## Pattern

1. **Parse the data** into a flat list of blocks (headings + items)
2. **Group in batches of ≤100 blocks** — respect year/section boundaries where possible (don't split a year across batches if avoidable)
3. **PATCH each batch** with `PATCH /v1/blocks/{page_id}/children`, 400ms delay between requests
4. **Use `ensure_ascii=False`** in `json.dumps` to preserve German umlauts

## Python template

```python
import json, subprocess, time

MAX_BLOCKS = 100
batches = []
current = []

for section in sections:
    heading = {"object": "block", "type": "heading_2",
               "heading_2": {"rich_text": [{"text": {"content": section.title}}]}}

    if len(current) + 1 + len(section.items) > MAX_BLOCKS:
        batches.append(current)
        current = []
    current.append(heading)

    for item in section.items:
        bullet = {"object": "block", "type": "bulleted_list_item",
                  "bulleted_list_item": {"rich_text": [{"text": {"content": item[:300]}}]}}
        current.append(bullet)
        if len(current) >= MAX_BLOCKS:
            batches.append(current)
            current = []

if current:
    batches.append(current)

# Send
for i, batch in enumerate(batches):
    payload = json.dumps({"children": batch}, ensure_ascii=False)
    subprocess.run([
        "curl", "-s", "-X", "PATCH",
        f"https://api.notion.com/v1/blocks/{page_id}/children",
        "-H", f"Authorization: Bearer {key}",
        "-H", "Notion-Version: 2025-09-03",
        "-H", "Content-Type: application/json",
        "-d", payload
    ], capture_output=True, text=True, timeout=60)
    time.sleep(0.4)
```

## Pitfalls

- **100-block hard limit:** Notion rejects ≥100 children in one PATCH. Always stay ≤99 or split at exactly 100.
- **Rate limiting:** 0.4s delay between batches avoids 429 responses even for 9+ batch runs.
- **Block type variety:** Mix `heading_2` + `bulleted_list_item` works. Adding `paragraph`, `divider`, or `quote` is fine — the limit counts all block objects equally.
- **Unicode:** Use `ensure_ascii=False` for German text (ä, ö, ü, ß, §). The Notion API accepts UTF-8 natively.
