> For the complete documentation index, see [llms.txt](https://k-ai.gitbook.io/knowledge-ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://k-ai.gitbook.io/knowledge-ai/sources-and-ingestion/connectors/notion.md).

# Notion

K-AI ingests pages and databases from a Notion workspace via the official Notion API. The connector traverses the workspace page tree, ingests block content, and resolves database rows as documents. Notion's permission model is workspace-centric, so ACLs are typically expressed at the workspace or page level.

## Supported source versions

Latest Notion API only (`Notion-Version` header, currently `2022-06-28`). The API evolves automatically — there is no version pinning on the K-AI side beyond the `Notion-Version` header sent on every request.

## Authentication

Authentication uses an **internal integration** token issued by a Notion workspace administrator. The integration is granted access to specific pages (and their descendants) by an explicit share action inside Notion — there is no global "read everything" permission.

OAuth (**public integration**) is also supported when K-AI ingests from multiple Notion workspaces under separate tenants — the consent screen requests the `read_content` and `read_user` scopes.

```
Authorization: Bearer secret_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Notion-Version: 2022-06-28
```

## Configuration

| Field              | Type      | Required | Description                                                                                                                                            |
| ------------------ | --------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `integrationToken` | string    | yes      | Internal integration secret (or OAuth bearer token). Encrypted at rest by the platform.                                                                |
| `workspaceId`      | string    | yes      | Notion workspace ID. Discovered via `/v1/users/me` if not provided.                                                                                    |
| `rootPageId`       | string    | no       | When set, restrict ingestion to the subtree rooted at this page. When unset, the connector enumerates every page the integration has been shared with. |
| `databaseIds`      | string\[] | no       | Restrict ingestion to a list of database IDs. Mutually exclusive with `rootPageId` when both narrow the same subtree.                                  |
| `includeArchived`  | boolean   | no       | Include archived pages and database rows. Default: `false`.                                                                                            |

## Document types ingested

* Notion **pages** — block content (paragraphs, headings, bulleted lists, toggles, code blocks, callouts) flattened to Markdown.
* Notion **database rows** — each row is one document. The row's properties become structural metadata.
* **File attachments** uploaded inside Notion blocks — downloaded and routed through the [indexation pipeline](/knowledge-ai/sources-and-ingestion/indexation-pipeline.md) as their native MIME type (PDF, DOCX, images).
* **Embeds** (Figma, YouTube, Loom) are recorded as metadata pointers only; the embedded resource is not fetched.

## Sync mode

Notion exposes a **search endpoint** (`POST /v1/search`) and a **databases query endpoint** (`POST /v1/databases/{id}/query`) that both accept a `filter.timestamp` clause on `last_edited_time`. The connector pages through pages and databases sorted by `last_edited_time desc`, stopping when it reaches the timestamp of the last successful sync.

The block tree of a changed page is re-fetched in full (Notion's API does not return a per-block diff). Deletions are detected by polling the `archived` flag.

## ACL handling

Notion's permission model is coarse:

* **Workspace level** — every workspace member can read every page the integration has been shared with.
* **Page level** — Notion supports per-page restrictions (Team plan and above). The connector reads `parent` and per-page share settings via `/v1/pages/{id}` to detect restricted pages.

The connector mirrors the resulting ACL onto the K-AI document record. Where Notion lacks fine-grained ACLs (Free / Plus workspaces), the connector applies the configured **mapping rule** (e.g. all documents → group `notion_workspace_readers`). At retrieval time, [K-AI MCP](/knowledge-ai/k-ai-mcp/mcp.md) replays the ACL against the calling identity.

## Rate limits & throttling

Notion enforces a **3 requests / second** average per integration. The connector caps concurrency at 3 and honours `429` responses with `Retry-After`. Bulk initial syncs of large workspaces (> 10k pages) typically run for several hours; this is expected behaviour, not a defect.

## Known limitations

* **Notion API granularity** — there is no true delta endpoint; the connector relies on `last_edited_time` polling, which can miss rapid edit-then-revert cycles between syncs.
* **Block-level permissions** are not exposed by the API; only page-level and workspace-level ACLs are mirrored.
* **Database schema changes** (column renames, type changes) require a manual re-index of the affected database.
* **Synced blocks** are followed once — the canonical content is ingested from the source block, references are recorded as metadata.
* **Free / Plus workspaces** have no per-page restrictions; all ingested documents inherit the workspace-level ACL.

## Setup walkthrough

1. **Create a Notion internal integration** at `https://www.notion.so/my-integrations`. Capture the **integration token** (`secret_...`).
2. **Share the target pages or databases** with the integration: in Notion, open the page → `...` menu → Connections → Add the K-AI integration. Sharing is recursive into child pages.
3. **Add the source in the K-AI admin portal**: select Notion, paste the `integrationToken`, optionally set `rootPageId` or `databaseIds`. Set the sync schedule (default: every 30 minutes).
4. **Trigger a test sync** and confirm the document count in the indexing statistics of the instance page in the K-AI Studio portal.
