apps/notion-clone, name notion) is an API-only clone of
the Notion public API: a NestJS backend on
Postgres that speaks Notion’s REST surface — integration-token Bearer auth
with a Notion-Version header, the workspace → users → databases → data sources →
pages → blocks → comments object model, Notion’s rich property/block JSON, cursor
pagination returning the {object:'list', results, has_more, next_cursor, type}
envelope, and Notion’s per-token rate limit (429 rate_limited + Retry-After).
@notionhq/client v5 can drive it (see SDK parity).
What’s inside
| Piece | Notes |
|---|---|
backend/ | NestJS REST API, integration-token Bearer auth, per-token rate limiter, Postgres via pg. Health at /api/health; API at /api/v1/.... |
supabase/migrations/ | 001_initial_schema.sql (workspaces, users, integration_tokens, databases, pages, blocks, comments) and 002_views_and_file_uploads.sql (file_uploads, views, view_queries) — run on spin and replayed on reset. |
seeds/ | acme-wiki.sql — the bundled deterministic fixture (an “Acme Wiki” workspace, a bot user + person users, a “Tasks” database, pages, blocks, comments, and a seeded integration token). |
Modes
| Mode | Services | Use it for |
|---|---|---|
api (default) | backend | Agents that talk to the REST API or the @notionhq/client SDK. |
Seeding
users, databases, and pages (the template’s declared
entities). See Seeding.
The seeded integration token
Unlike a browser OAuth install flow, the clone seeds an integration token so the firstcurl or SDK call authenticates with zero setup (there is no
signup/consent route):
Notion-Version header:
Notion-Version header returns the real Notion error
(400 missing_version); a present header is accepted regardless of value
(known versions 2022-06-28 / 2025-09-03 / 2026-03-11 are recognized,
unknown ones are normalized rather than rejected) so modern SDKs keep working.
Invalid or missing Bearer tokens return 401 {code:'unauthorized'}.
Rate limiting
Like real Notion, the clone enforces a per-integration-token rate limit (token bucket, ~3 requests/second). Bursting past it returns Notion’s throttle response byte-for-byte:529 service_overload path also exists (env-gated). The health probe
is exempt. Agents that retry on Retry-After — as the official SDK does — work
unchanged.
SDK parity
An unmodified@notionhq/client v5+ (which sends Notion-Version: 2026-03-11) works against the clone when constructed with the clone’s baseUrl:
data_sources-routed calls (dataSources.query, parent.data_source_id,
search({filter:{property:'object',value:'data_source'}})) resolve.
API shape — read this before pointing an agent at it
The clone is a path-faithful subset of Notion’s REST API under the/api/v1
prefix (POST /api/v1/pages, POST /api/v1/databases/:id/query, …). The
template ships an API_PARITY.md that scores it against Notion’s live docs
(re-fetched every audit, never from memory). The implemented core covers:
- Users —
me, list, retrieve. - Databases — create / retrieve / update / query (with a documented
filter-operator allowlist; unsupported operators return a
400validation error rather than silently returning all rows). - Data sources (2025-09-03 split) — create / retrieve / update / query.
- Pages — create / retrieve / update (incl. trash via
in_trash) / property item / move / Markdown read + write. - Blocks — retrieve / list children / append children / update / delete.
- Comments — create / list / retrieve / update / delete.
- Search — pages + databases by title, with the
data_sourceobject alias. - File uploads — create / list / retrieve / send / complete.
- Views — create / list / retrieve / update / delete, plus view queries (create / retrieve / delete).
- OAuth token endpoints —
oauth/token(incl.grant_type=refresh_token) /oauth/introspect/oauth/revoke.
mcp.notion.com), and relation/rollup/formula compute — are
unimplemented by design; the clone never claims to emit events or ship MCP tools.
See apps/notion-clone/API_PARITY.md for the per-endpoint breakdown and the
filter-operator allowlist.
The
verify command will fold live fidelity scoring into
the CLI. Until then, API_PARITY.md and the /verify-api workflow are how
fidelity is tracked.