# Notion

Notion is an all-in-one workspace for notes, databases, wikis, and project management. The Sling Notion connector extracts data from the Notion REST API, supporting pages, databases, blocks (content), users, and comments.

{% hint style="success" %}
**CLI Pro Required**: APIs require a [CLI Pro token](https://docs.slingdata.io/sling-cli/cli-pro) or [Platform Plan](https://docs.slingdata.io/sling-platform/platform).
{% endhint %}

## Setup

The following credentials are accepted:

**Secrets:**

* `api_key` **(required)** -> Your Notion Internal Integration Token

### Getting Your Integration Token

1. Go to [My Integrations](https://www.notion.so/profile/integrations) in your Notion settings
2. Click "Create new integration"
3. Give it a name (e.g., "Sling Integration")
4. Select the workspace you want to connect
5. Under **Capabilities**, ensure these are enabled:
   * **Read content** — required for pages, databases, and blocks
   * **Read comments** — required for the comments endpoint
   * **Read user information including email addresses** — required for the users endpoint
6. Click "Save" and copy the Internal Integration Secret (starts with `ntn_`)

{% hint style="warning" %}
**Important:** Notion integrations must be explicitly added to each page or database you want to access. Open a page in Notion, click the **⋯** menu → **Connections** → search for your integration name → add it. Child pages inherit the connection automatically.
{% endhint %}

### Using `sling conns`

Here are examples of setting a connection named `NOTION`. We must provide the `type=api` property:

{% code overflow="wrap" %}

```bash
sling conns set NOTION type=api spec=notion secrets='{ api_key: ntn_xxxxxxxxxxxx }'
```

{% endcode %}

### Environment Variable

See [here](https://docs.slingdata.io/sling-cli/environment#dot-env-file-.env.sling) to learn more about the `.env.sling` file.

{% code overflow="wrap" %}

```bash
export NOTION='{ type: api, spec: notion, secrets: { api_key: "ntn_xxxxxxxxxxxx" } }'
```

{% endcode %}

### Sling Env File YAML

See [here](https://docs.slingdata.io/sling-cli/environment#sling-env-file-env.yaml) to learn more about the sling `env.yaml` file.

```yaml
connections:
  NOTION:
    type: api
    spec: notion
    secrets:
      api_key: "ntn_xxxxxxxxxxxx"
```

## Replication

Here's an example replication configuration to sync Notion data to a PostgreSQL database:

```yaml
source: NOTION
target: MY_POSTGRES

defaults:
  mode: full-refresh
  object: notion.{stream_name}

streams:
  # sync all endpoints
  '*':
```

**Incremental sync for pages and databases:**

```yaml
source: NOTION
target: MY_POSTGRES

defaults:
  object: notion.{stream_name}

streams:
  users:
    mode: full-refresh

  databases:
    mode: incremental

  pages:
    mode: incremental

  blocks:
    mode: full-refresh

  comments:
    mode: full-refresh
```

## Endpoints

| Endpoint    | Description                                                      | Incremental | Depends On |
| ----------- | ---------------------------------------------------------------- | ----------- | ---------- |
| `users`     | All users in the workspace (people and bots)                     | No          | —          |
| `databases` | All databases shared with the integration                        | Yes         | —          |
| `pages`     | All pages shared with the integration (including database rows)  | Yes         | —          |
| `blocks`    | Content blocks (paragraphs, headings, lists, etc.) for each page | No          | `pages`    |
| `comments`  | Comments on each page                                            | No          | `pages`    |

The `blocks` and `comments` endpoints are **child endpoints** — they iterate over all page IDs collected by the `pages` endpoint. This means the `pages` endpoint must run first to populate the queue.

To discover available endpoints:

```bash
sling conns discover NOTION
```

### Endpoint Details

**`users`** — Returns workspace members and bot integrations. Includes name, email (if permission granted), avatar URL, and user type (person or bot).

**`databases`** — Returns database metadata including title, properties schema, and parent information. Supports incremental sync via `last_edited_time`. Database IDs are also queued for potential child endpoint use.

**`pages`** — Returns all pages the integration can access, including standalone pages and database rows. Supports incremental sync via `last_edited_time`. Page IDs are queued for the `blocks` and `comments` child endpoints.

**`blocks`** — Returns content blocks for each page. Block types include paragraphs, headings, lists, to-dos, toggles, images, code blocks, and more. Each record includes a `_page_id` field linking it back to the parent page.

**`comments`** — Returns comments on each page. Each record includes the comment text, author, timestamps, and a `_page_id` field linking it to the parent page.

## Incremental Sync

The `databases` and `pages` endpoints support incremental sync using the `last_edited_time` field:

* **First run:** Fetches all records shared with the integration
* **Subsequent runs:** Only fetches records edited after the last sync timestamp

The `users`, `blocks`, and `comments` endpoints always run in full-refresh mode since they don't support server-side time-based filtering.

## Rate Limiting

The Notion API has rate limits:

* **All requests:** 3 requests per second

The connector automatically:

* Uses conservative rate limiting (3 requests/second with concurrency of 1)
* Retries with exponential backoff on 429 (rate limit) responses
* Allows up to 5 retry attempts

## Sharing Pages with the Integration

Unlike some APIs where a token grants access to all data, Notion requires you to explicitly share pages and databases with your integration:

1. Open a page or database in Notion
2. Click the **⋯** (three-dot) menu in the top right
3. Select **Connections**
4. Search for your integration name and select it
5. Confirm the capabilities

Child pages and databases within a shared page automatically inherit access. To grant access to your entire workspace, share each top-level page.

## Common Use Cases

### Sync All Notion Data

```yaml
source: NOTION
target: MY_POSTGRES

defaults:
  mode: full-refresh
  object: notion.{stream_name}

streams:
  '*':
```

### Sync Pages and Databases Incrementally

```yaml
source: NOTION
target: MY_POSTGRES

defaults:
  object: notion.{stream_name}

streams:
  databases:
    mode: incremental
  pages:
    mode: incremental
```

### Extract Page Content for Search or Analysis

```yaml
source: NOTION
target: MY_POSTGRES

defaults:
  mode: full-refresh
  object: content.{stream_name}

streams:
  pages:
  blocks:
```

### Sync Workspace Members

```yaml
source: NOTION
target: MY_POSTGRES

defaults:
  mode: full-refresh

streams:
  users:
    object: notion.users
```

If you are facing issues connecting, please reach out to us at <support@slingdata.io>, on [discord](https://discord.gg/q5xtaSNDvp) or open a Github Issue [here](https://github.com/slingdata-io/sling-cli/issues).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.slingdata.io/connections/api-connections/notion.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
