> ## Documentation Index
> Fetch the complete documentation index at: https://docs.serval.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Notion

> Connect your Notion workspace to Serval to power workflow automation and sync your shared pages and databases into Serval's knowledge base.

## About Notion

Serval's Notion integration connects a Notion workspace to Serval so workflows can search and read your Notion content, and so pages and databases shared with the integration can be ingested into Serval's knowledge base. Serval stores your credentials securely and attaches them to every call on your behalf - all traffic goes only to Notion's official API host (`api.notion.com`). The integration also installs one ready-to-use workflow, **Search and Read Notion Pages**, which finds relevant pages and reads their full content so it can be used to answer questions.

**Authentication:** Serval-managed OAuth (recommended), a bring-your-own Notion public integration, or a Notion internal integration secret (API key). All three behave identically once connected.

**Data sync:** Background knowledge sync of every page and database shared with the integration. After the first full sync, items are only re-synced when they have been edited in Notion (or when a previous sync attempt didn't complete). You can also trigger a manual sync from the Serval UI at any time.

## What the Notion integration enables

| Capability                                    | Description                                                                                                                                                                                                                                                                                                                                              |
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Workflow API access                           | Serval workflows can call any Notion API operation through Serval's built-in Notion action, with your credentials injected automatically.                                                                                                                                                                                                                |
| Knowledge sync                                | Pages and databases - including database rows that Notion's own search misses - are ingested into Serval's knowledge base as Markdown, with parent-child relationships preserved and incremental re-sync when content changes. Accepting a [knowledge suggestion](/sections/documentation/suggestions/overview) also creates or updates pages in Notion. |
| Seeded workflow: Search and Read Notion Pages | Installed automatically with the integration and runs without requiring approval. It searches for pages matching the request - most recently edited first - then reads their content: paragraphs, headings, lists, to-dos, toggles, tables, code, callouts, and more - so the answers come from the actual page text.                                    |
| Health checks                                 | Three built-in checks verify connectivity, workspace user listing, and content visibility. See [Verifying the connection](#verifying-the-connection).                                                                                                                                                                                                    |

Anything defined in the [Notion API](https://developers.notion.com/reference/intro) can be accessed through Serval.

## Get your credentials

What you need depends on which connect option you choose. All Notion integrations are created and managed from the [Notion integrations dashboard](https://www.notion.so/profile/integrations).

<Tabs>
  <Tab title="Serval-managed OAuth (recommended)">
    Nothing to create. You'll sign in to Notion in a popup, choose a workspace, and pick which pages to share - Serval handles everything else. Skip ahead to [Connect in Serval](#connect-in-serval).
  </Tab>

  <Tab title="Internal integration secret (API key)">
    <Steps>
      <Step title="Create an internal integration">
        Open the [Notion integrations dashboard](https://www.notion.so/profile/integrations) and click **New integration**.
      </Step>

      <Step title="Set the type and capability">
        Set the type to **Internal** and enable the **Read content** capability.
      </Step>

      <Step title="Copy the secret">
        On the integration's settings page, go to **Configuration → Internal Integration Secret** and copy the secret (it starts with `ntn_`, or `secret_` for older integrations).
      </Step>

      <Step title="Share content with the integration">
        In Notion, open each page or database Serval should read and use **••• → Connections** to connect your integration. Child pages inherit the connection automatically.
      </Step>
    </Steps>

    <Warning>
      The integration needs the **Read content** capability and must be connected to at least one page before Serval can read anything. Serval validates the secret itself when you connect - an invalid secret is rejected immediately - but it cannot check page sharing for you: with nothing shared, the connection succeeds and syncs and searches simply come back empty.
    </Warning>
  </Tab>

  <Tab title="Bring your own (public integration)">
    <Steps>
      <Step title="Create or open a public integration">
        Open the [Notion integrations dashboard](https://www.notion.so/profile/integrations) and click **New integration**, or open an existing public integration.
      </Step>

      <Step title="Set the type to Public">
        Set the integration type to **Public** - only public Notion integrations support OAuth.
      </Step>

      <Step title="Register Serval's Redirect URI">
        Copy the **Redirect URI** shown in Serval's connect modal and paste it into the integration's **Redirect URIs** list in Notion, then save. Notion requires an exact, character-for-character match.
      </Step>

      <Step title="Copy the client credentials">
        From the **OAuth Domain & URIs** section of the integration's settings page, copy the **OAuth client ID** and the **OAuth client secret** (click **Show** next to the secret).
      </Step>
    </Steps>

    <Note>
      If you have an *internal* Notion integration, use the API-key path instead - it ends up with the same access and behaves identically at runtime.
    </Note>
  </Tab>
</Tabs>

## Connect in Serval

Open the Notion integration in Serval and pick one of the three options in the connect modal.

<Tabs>
  <Tab title="Sign in with Notion (OAuth)">
    <Steps>
      <Step title="Choose the OAuth option">
        Select **Sign in with Notion (OAuth)**.
      </Step>

      <Step title="Authorize in the popup">
        Sign in to Notion, choose the workspace to connect, and pick the pages to share with Serval. There is no permissions screen to review - Notion OAuth has no scopes; access is governed entirely by which workspace you select and which pages you share.
      </Step>

      <Step title="Confirm the new connection">
        The connection is named after your Notion workspace, with your email in parentheses when Notion provides it - for example, a workspace called Acme connected by [jane@acme.com](mailto:jane@acme.com) appears as Acme ([jane@acme.com](mailto:jane@acme.com)). If a teammate connects the same workspace, they get their own separate connection; this is expected.
      </Step>
    </Steps>
  </Tab>

  <Tab title="Use your own Notion integration">
    <Steps>
      <Step title="Register the Redirect URI first">
        Select **Use your own Notion integration**. The modal shows a read-only **Redirect URI** field with a **Copy** button - copy it into your Notion integration's Redirect URIs list and save *before* continuing. Always copy rather than type; Notion rejects anything that isn't an exact match.
      </Step>

      <Step title="Fill in the form">
        * **Display name** (optional) - a friendly name shown in Serval, e.g. "My Company Notion". You choose this.
        * **OAuth client ID** (required) - found in the OAuth Domain & URIs section of your Notion integration's settings page.
        * **OAuth client secret** (required) - a password field, placeholder `secret_...`. Click **Show** next to the secret in Notion to reveal it before copying.

        The **Connect** button stays disabled until both required fields are filled in.
      </Step>

      <Step title="Finish in Notion promptly">
        Click **Connect** and complete the Notion authorization as the installing user, choosing the workspace. Your submitted credentials are held for only **10 minutes** - if the Notion step takes longer, the connection fails with "Invalid or expired OAuth state" and you must re-submit the form.
      </Step>
    </Steps>

    <Note>
      When reconnecting, the **Display name** and **OAuth client ID** are pre-filled, but the **OAuth client secret** is never pre-filled - you must re-enter it every time.
    </Note>
  </Tab>

  <Tab title="Use an internal integration secret (API key)">
    <Steps>
      <Step title="Choose the API key option">
        Select **Use an internal integration secret (API key)**.
      </Step>

      <Step title="Paste the secret">
        Enter your secret in the **Internal Integration Secret** field - a password field with placeholder `ntn_...`. The **Connect** button stays disabled until you've entered a value.
      </Step>

      <Step title="Connect and wait for validation">
        Click **Connect**. Serval validates the secret live against Notion (up to 15 seconds) *before* saving anything. If the secret is invalid, or isn't actually an internal integration secret (for example, a pasted user OAuth token), the connection fails immediately with: "Could not verify this Notion secret. Make sure it's a valid Internal Integration Secret with read content access, and that the integration is connected to at least one page."
      </Step>
    </Steps>

    <Note>
      The connection's identity is tied to the integration's bot user, so rotating the secret later updates the same connection rather than creating a duplicate. When rotating, paste the **complete** new secret - Serval re-validates whatever you submit and never falls back to the stored secret, so a blank field fails with "A Notion internal integration secret is required." and a masked value fails verification. A blank field does **not** keep the old secret.
    </Note>
  </Tab>
</Tabs>

## Verifying the connection

After connecting, run the integration's health checks:

* **Test Notion Connection** - verifies basic connectivity and authentication by fetching the integration's bot user.
  * Success: "Successfully connected to Notion as "\[name]"" (the name falls back to "Unknown" when Notion returns no name)
  * Failure: "Unable to connect to Notion. Please verify your integration token and permissions are correct."
* **List Notion Users** - verifies the integration can list users in the workspace.
  * Success: "Successfully listed users from Notion (found \[number])"
  * Failure: "Unable to list users from Notion. Please verify your integration has access to the workspace."
* **Search Notion Content** - verifies the integration can search pages and databases.
  * Success: "Successfully searched Notion content (found \[number] items)" - with ", more available" appended inside the parentheses when more results exist
  * Failure: "Unable to search content in Notion. Please verify your integration has access to pages and databases."

<Tip>
  The most common "all checks green but nothing syncs" cause: **Search Notion Content** succeeds even when it finds **zero** items. Read the count in the success message - "found 0 items" means authentication works but no content has been shared with the integration yet.
</Tip>

## Gotchas and troubleshooting

<AccordionGroup>
  <Accordion title="Notion only shows Serval what has been explicitly shared with the integration">
    This is the #1 source of Notion confusion. Every read path - knowledge sync, the **Search Notion Content** health check, and the seeded search workflow - sees only pages and databases connected to the integration. There is no workspace-wide crawl. A successful connect with nothing shared yields an empty knowledge sync and "Successfully searched Notion content (found 0 items)". Share content in Notion via **••• → Connections** on each top-level page or database; child pages inherit the connection. (Adding a connection to a page requires edit access on that page - that's Notion's rule, not Serval's.) For the OAuth path, the page picker on Notion's authorize screen controls the initial grant.
  </Accordion>

  <Accordion title="A passing search health check does not mean content is available">
    **Search Notion Content** reports success regardless of how many items it finds. The found-count in the message is the real signal - "found 0 items" means the credentials work but nothing is shared with the integration yet.
  </Accordion>

  <Accordion title="First sync waits 30 seconds, and newly shared pages can lag">
    On a knowledge source's first sync, Serval deliberately waits 30 seconds for Notion's search indexing before searching. Pages newly shared with the integration can also take time to appear in Notion's search index, so a sync triggered immediately after sharing may miss them - re-sync if a just-shared page is absent.
  </Accordion>

  <Accordion title="The API-key path validates the secret at connect time and requires a real integration secret">
    Serval verifies the pasted secret against Notion before saving anything. An invalid secret - or any token that isn't a real internal integration secret (for example, a pasted user OAuth token) - fails immediately with: "Could not verify this Notion secret. Make sure it's a valid Internal Integration Secret with read content access, and that the integration is connected to at least one page." Note that this check validates the secret itself; it cannot tell whether any pages have actually been shared with the integration yet.
  </Accordion>

  <Accordion title="Editing credentials requires full re-entry - blank does not keep the old secret">
    When rotating the Internal Integration Secret, Serval re-validates whatever you submit and never falls back to the stored value - a blank field fails with "A Notion internal integration secret is required." and a masked value fails verification. Paste the complete new secret. Similarly, reconnecting a bring-your-own integration pre-fills only the Display name and OAuth client ID - the OAuth client secret must be re-entered every time.
  </Accordion>

  <Accordion title="Custom-app Redirect URI must match exactly, and form credentials expire after 10 minutes">
    Notion rejects any redirect URI that doesn't exactly match a registered one. Always copy the URI from Serval's connect modal rather than typing it. Your submitted client ID and secret are held for only 10 minutes - if the Notion authorize step takes longer, the connection fails with "Invalid or expired OAuth state" and you must re-submit the form.
  </Accordion>

  <Accordion title="Bring-your-own requires a public Notion integration">
    Only *public* Notion integrations support OAuth. If you have an internal integration, use the API-key path instead - both end up with the same access and behave identically at runtime.
  </Accordion>

  <Accordion title="No OAuth scopes - don't look for a permissions screen">
    The OAuth flow requests no scopes and Notion returns none. Access is controlled entirely by which workspace you select at authorize time, plus per-page sharing afterwards.
  </Accordion>

  <Accordion title="OAuth connections are identified per user, not just per workspace">
    OAuth and bring-your-own connections are identified by workspace *and* the connecting user's email, and named after the workspace with the connecting user's email in parentheses. Two teammates connecting the same Notion workspace create two distinct connections. This is expected behavior, not a duplicate-connection bug.
  </Accordion>
</AccordionGroup>

***

Need help? Contact **[support@serval.com](mailto:support@serval.com)** for assistance with your Notion integration.
