Buff Development
Connector

Notion

Notion pages and databases as context for answers: reading, questions in comments, the research report as a page, scope, webhook and polling.

For a team, Notion is the same as Confluence: written context that is in neither the task nor the code. Requirements, decisions, policies, runbooks — and tables: the Notion databases where the team keeps tasks, registers and agreements. The integration lets the model read all of this when an answer needs it, takes questions right in page comments and can leave the result as a page, not only as a comment.

A question whose answer is written down only in Notion: the model went to the page with a tool and answered from it.

Tools

ToolWhat it does
search_pagessearches pages and databases by words — in titles through Notion’s search and in the text of pages in scope on its own: Notion searches only titles, while a question is usually about what the page says. Words are compared by their stem, so inflections do not get in the way; a page is read once until its next edit
get_pagereads a whole page — as markdown with headings, lists, tables and code — together with its discussion
get_page_childrenlists the nested pages and databases of a section
get_databasethe structure of a database: its data sources and properties with types
query_databasedatabase records — each with its properties as text; optionally with a filter on one property, in Notion’s dialect for its type
get_commentsthe page’s discussions: threads, who wrote and when
add_commenta comment on a page or a reply in a thread
create_pagea child page from markdown — within the connection’s scope

The first six only read and are available wherever the model is given connector tools — in “Ask” and in deep research. The two writing ones are not given to the model at any stage: the connector itself uses them when, at the platform’s command, it returns an answer as a comment or a research report as a child page — and only within the scope.

A page arrives as markdown, not as a block tree. Since API version 2026-03-11 Notion returns and accepts a page in one call in its own markdown; the integration adds nothing to it and truncates nothing — a long page stays long. A database record arrives flat: each property as text, according to its type (a status — by name, a date — as a date, a checkbox — “yes”/“no”).

Requests on a page

Everything described in “Tracker integrations” works here too: @buff <question>, @buff research …, @buff task … or /ask, /research, /task in a page comment is a question, a research or a task draft. The answer arrives in the same discussion thread; a question in a new thread starts a new conversation.

In Notion the integration cannot be mentioned with @: it is not a person and does not appear in the suggestions. The bot is addressed with a word in the text — the alias from the settings (buff) or the integration’s name. Both are written as is; case does not matter.

A page has no code branch, so the answer is computed at the level of the development project — or space — that the connection is bound to.

Research — as a page

The answer to /research in Notion does not go into a comment: under the page where the question was asked, a child page with the report appears — the text itself, not a picture of text — and a PDF document is attached to it. A comment with a link to the report and to the research in Buff arrives in the discussion thread. The page is created only within the scope.

Scope

The connection lists roots — links or identifiers of pages and databases. The bot works in them and in everything nested: a page counts as “in scope” if one of its parents is a root (page → page → database → page …). Writing is limited the same way: you cannot reply, create a page or a comment outside the scope.

An empty list of roots means “everything open to the integration in Notion”. Here the boundary has already been drawn by Notion itself: the integration sees only the pages it was connected to. This differs from trackers, where an empty list means “nowhere” — the semantics are decided for each source separately.

The integration’s permissions in Notion are the outer boundary, the list of roots is the inner one; it is sensible to have both: connect the integration to a section, not to the whole workspace.

Events: webhook and polling

Notion has no comment feed for a workspace, and a new comment does not change the page. So events work differently than for Confluence and Figma:

  • The webhook is parsed. The comment.created event names the comment, the integration reads it through the API and answers within seconds. The receiver belongs to the connector, and it issues the link — see tracker events.
  • Polling is a safety net. The integration goes round the pages in scope, a few per pass, and reads their comments. By default every 5 seconds: the interval is a connection setting, and for Notion the integration suggests five seconds. An idle pass costs one request; with Notion’s limit of 180 requests per minute per integration (600 on the Business and Enterprise plans) this fits with room to spare, and the integration waits out 429 answers as Retry-After asks.

The signing token comes from Notion

Notion signs its calls with its own verification token, not with the secret from the link: when a subscription is created, it makes one unsigned call with a verification_token, and that has to be pasted into the confirmation form in Notion. The connector does this for you:

  1. Turn on webhook reception for the connection and copy the issued link.
  2. In the Notion integration settings (Webhooks) enter this link. Notion sends the token.
  3. Open the connection in the connector: the token is already there, with a “Copy” button. Paste it into Notion and confirm the subscription; subscribe to the comment.created event.

From then on the connector checks every call’s X-Notion-Signature header with this token. If the subscription is recreated, Notion sends a new token — the connector does not silently replace the old one with it: it shows the new one on the connection page and keeps checking calls with the old one until you accept the new one in the “Signing secret” field.

The setup form: the API address is already filled in; what remains is to name the roots, the polling interval and the integration token.

Setup

In Notion

  1. Create an internal integration in the workspace settings (the “Integrations” → “Develop” section). It needs these capabilities: read content, insert content, read and insert comments; reading user information is optional — it provides authors’ names where Notion did not fill them in.
  2. Copy the integration secret — this is the token for the “api” field in the connector.
  3. Connect the integration to pages: on the section’s root page (or database), the “…” menu → “Connections” → choose the integration. Everything nested opens up along with it.

In the connector

FieldValue
API addressprefilled: https://api.notion.com — no need to change it
api credentialsthe internal integration’s secret
Pages and databaseslinks or identifiers of the roots, comma-separated; empty — everything open to the integration
Other ways to address the bota short name, for example buff
Polling intervalseconds; empty — as the integration suggests, 5

The connectivity check says not “ok” but the workspace name, the integration name, how many roots are in scope and how many of them are actually available to it.

From the command line: connector install notion, then connector instance set --plugin notion --version 1.0.0 --set roots=<link>,<link> --poll 5.

Connectivity check: the workspace, the integration and how many roots are available.

What the integration does not do

  • It does not edit existing pages and database records — it only reads them, writes comments and creates new pages within the scope.
  • It does not copy or index Notion content to us: what a particular answer needed is read and goes into that answer’s context.
  • It does not index in advance — the text search reads the pages in scope at the moment of the question (once until the page’s next edit); in a large scope the first search takes time.
  • It does not run tasks in Notion as a tracker would: a database is read as knowledge, and the bot does not move statuses in it.

On this page