Skip to content
← Public packages

@kentcdodds/notion

Search, read, query, and safely write Notion pages and databases across multiple workspaces via notion / notion-* OAuth integrations.

AGENTS.md

109 lines · 3.5 KB · Markdown
Raw

@kentcdodds/notion — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke/dryRun snippets, and edge cases. Auth is OAuth integrations named notion / notion-* — never paste tokens. Do not disable live webhooks or jobs.

Auth / integrations

CallResolves to
omit bothnotion (default)
account: 'work'notion-work
integration: 'notion-work'that exact name
account already notion-…used as-is

Reconnect: /connect/oauth?provider=notion or ...?provider=notion-<purpose>.

Import paths

ExportImport
overviewkody:@kentcdodds/notion
accountskody:@kentcdodds/notion/accounts
smoke-testkody:@kentcdodds/notion/smoke-test
requestkody:@kentcdodds/notion/request
searchkody:@kentcdodds/notion/search
get-pagekody:@kentcdodds/notion/get-page
get-block-childrenkody:@kentcdodds/notion/get-block-children
get-databasekody:@kentcdodds/notion/get-database
get-data-sourcekody:@kentcdodds/notion/get-data-source
query-databasekody:@kentcdodds/notion/query-database
create-pagekody:@kentcdodds/notion/create-page
append-block-childrenkody:@kentcdodds/notion/append-block-children

Prefer static kody:@kentcdodds/notion/... imports from execute.

Smoke test (read-only)

import smokeTest from 'kody:@kentcdodds/notion/smoke-test'

export default async function main() {
	return await smokeTest()
	// => { ok: true, tokenType, hasBotOwner } — no workspace/user PII
}

Optional account listing:

import listNotionAccounts from 'kody:@kentcdodds/notion/accounts'

export default async function main() {
	return await listNotionAccounts()
}

dryRun / confirm (writes)

Mutating helpers and mutating request methods require confirm: true after explicit user approval of destination and content. Use dryRun: true to preview without calling Notion.

import createPage from 'kody:@kentcdodds/notion/create-page'

export default async function main() {
	return createPage({
		account: 'personal',
		parent: { database_id: '00000000-0000-0000-0000-000000000000' },
		properties: {
			Name: { title: [{ text: { content: 'New page' } }] },
		},
		dryRun: true,
	})
}
import search from 'kody:@kentcdodds/notion/search'

export default async function main() {
	return await search({
		query: 'meeting notes',
		objectType: 'page',
		account: 'work',
	})
}

Edge cases

  • Notion-Version 2026-03-11: databases are containers; schema/rows live on data sources. get-database → data_sources; get-data-source for properties; query via data source. Helpers that take databaseId auto-resolve a single data source and error if there are several.
  • Database-row pages need parent: { data_source_id } (or database_id for auto-resolve on create-page).
  • Search returns data_source objects where databases used to appear — filter with objectType: 'page' | 'data_source'.
  • Block position: position: { type: 'after_block' | 'start' | 'end', ... } — flat after is gone. Trash field is in_trash (no archived).
  • Inline child databases: use request POST /databases with is_inline: true and initial_data_source.properties — not append-block-children.
  • Do not round-trip saved formula expression values; keep the human-readable form in your source of truth.
  • List helpers: pageSize 1–100, startCursor; responses include hasMore / nextCursor.