← Back to all products
$29
Notion API Automation System
Python scripts and Zapier integrations for automating Notion: auto-create pages, sync databases, generate reports, and send notifications.
PythonConfigMarkdownJSONYAMLAWSNotion
📄 Product Preview
Try the interactive reader and demo tools below, or get the full product with all content unlocked.
📖 Interactive Reader (Free Preview) ⚙ Try Demo Tools 📦 Download Free Sample📁 File Structure 46 files
notion-automation-system/
├── LICENSE
├── README.md
├── configs/
│ └── automation_rules.yaml
├── examples/
│ ├── __pycache__/
│ │ ├── cross_db_sync.cpython-312.pyc
│ │ ├── daily_standup_page.cpython-312.pyc
│ │ ├── database_backup.cpython-312.pyc
│ │ ├── stale_task_alerter.cpython-312.pyc
│ │ └── weekly_metrics_report.cpython-312.pyc
│ ├── cross_db_sync.py
│ ├── daily_standup_page.py
│ ├── database_backup.py
│ ├── stale_task_alerter.py
│ └── weekly_metrics_report.py
├── free-sample.zip
├── guide/
│ ├── 01_SCHEDULING.md
│ ├── 02_SETUP.md
│ └── 03_ZAPIER_GUIDE.md
├── guides/
│ ├── SCHEDULING.md
│ ├── SETUP.md
│ └── ZAPIER_GUIDE.md
├── index.html
├── integrations/
│ ├── zapier_db_to_slack.json
│ ├── zapier_form_to_notion.json
│ └── zapier_new_page.json
├── requirements.txt
├── src/
│ ├── __init__.py
│ ├── __pycache__/
│ │ ├── __init__.cpython-312.pyc
│ │ ├── client.cpython-312.pyc
│ │ ├── databases.cpython-312.pyc
│ │ ├── filters.cpython-312.pyc
│ │ ├── notifications.cpython-312.pyc
│ │ ├── pages.cpython-312.pyc
│ │ ├── reports.cpython-312.pyc
│ │ └── sync_engine.cpython-312.pyc
│ ├── client.py
│ ├── databases.py
│ ├── filters.py
│ ├── notifications.py
│ ├── pages.py
│ ├── reports.py
│ └── sync_engine.py
└── tests/
├── __pycache__/
│ ├── test_client.cpython-312.pyc
│ └── test_filters.cpython-312.pyc
├── test_client.py
└── test_filters.py
📖 Documentation Preview README excerpt
Notion API Automation System
Automate your Notion workspace with Python scripts, scheduled reports, and webhook-driven workflows.
Stop manually creating pages, copying data between databases, and formatting reports. This system gives you a complete Python toolkit for Notion API automation — from simple page creation to multi-database sync engines and Zapier/webhook integrations.
What You Get
- Notion API client wrapper — handles authentication, rate limiting, pagination, and retry logic so you never hit the API raw
- Page & database CRUD helpers — create, read, update, archive pages and query databases with Pythonic filters
- Report generator — pull data from Notion databases and render Markdown/HTML summary reports on a schedule
- Notification sender — send Slack, email, or webhook alerts when Notion data meets your trigger conditions
- Sync engine — bidirectional sync between two Notion databases (or between Notion and a local JSON/CSV cache)
- Zapier integration recipes — pre-built Zapier webhook configurations for common Notion automations
- Runnable examples — 5 real scripts you can adapt: daily standup page, weekly metrics report, stale-task alerter, database backup, and cross-database sync
- Config-driven design — one
.envfile for credentials, one YAML file for all automation rules
File Structure
notion-automation-system/
├── README.md
├── LICENSE
├── requirements.txt
├── src/
│ ├── __init__.py
│ ├── client.py # Notion API client with rate limiting & retries
│ ├── pages.py # Page creation, update, archive helpers
│ ├── databases.py # Database query, filter builder, schema reader
│ ├── reports.py # Report generation from database queries
│ ├── notifications.py # Alert dispatch (Slack, email, webhook)
│ ├── sync_engine.py # Cross-database and Notion-to-local sync
│ └── filters.py # Notion filter/sort DSL builder
├── examples/
│ ├── daily_standup_page.py # Auto-create a standup page every morning
│ ├── weekly_metrics_report.py# Pull KPIs and generate a summary report
│ ├── stale_task_alerter.py # Notify when tasks haven't been updated
│ ├── database_backup.py # Export a Notion database to JSON/CSV
│ └── cross_db_sync.py # Sync records between two databases
├── configs/
│ ├── .env.example # API keys and integration tokens
│ └── automation_rules.yaml # Declarative automation configuration
├── integrations/
│ ├── zapier_new_page.json # Zapier: webhook creates Notion page
│ ├── zapier_db_to_slack.json # Zapier: Notion DB change → Slack message
│ └── zapier_form_to_notion.json # Zapier: form submission → Notion page
├── guides/
│ ├── SETUP.md # Getting started guide
│ ├── ZAPIER_GUIDE.md # How to wire up the Zapier integrations
│ └── SCHEDULING.md # Running scripts on a cron schedule
└── tests/
├── test_client.py # Unit tests for the API client
└── test_filters.py # Unit tests for the filter builder
Quick Start
1. Get Your Notion API Token
... continues with setup instructions, usage examples, and more.
📄 Code Sample .py preview
src/client.py
"""
Notion API Client
==================
Wraps the Notion REST API (version 2022-06-28) with automatic rate-limit
handling, pagination, exponential backoff, and structured error responses.
Why a wrapper instead of calling requests directly?
- Notion's rate limit is 3 requests/second for integrations. If you
blast the API from a loop, you'll get 429s and lose data. This client
tracks request timing and sleeps proactively.
- Paginated endpoints (database queries, block children) require you to
follow `next_cursor` tokens. The client does this transparently.
- Error responses from Notion have a specific JSON shape. The client
parses them into a typed NotionAPIError so your scripts get clean
exceptions instead of raw HTTP status codes.
Usage:
from src.client import NotionClient
client = NotionClient() # reads NOTION_TOKEN from .env
client = NotionClient(token="ntn_...") # or pass explicitly
page = client.get_page("page-id-here")
results = client.query_database("db-id", filter_obj={...})
"""
from __future__ import annotations
import json
import logging
import os
import time
from dataclasses import dataclass
from pathlib import Path
from typing import Any
# We use urllib from stdlib so the package has zero hard dependencies.
# If `requests` is installed (it's in requirements.txt), we prefer it
# for connection pooling. Otherwise we fall back to urllib.
try:
import requests as _requests_lib
_HAS_REQUESTS = True
except ImportError:
_HAS_REQUESTS = False
import urllib.request
import urllib.error
logger = logging.getLogger(__name__)
# ... 351 more lines ...