Agent Skills: Notion SDK Patterns

'Apply production-ready @notionhq/client SDK patterns for TypeScript

UncategorizedID: jeremylongshore/claude-code-plugins/notion-sdk-patterns

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/notion-pack/skills/notion-sdk-patterns

Skill Files

Browse the full folder contents for notion-sdk-patterns.

Download Skill

Loading file tree…

plugins/saas-packs/notion-pack/skills/notion-sdk-patterns/SKILL.md

Skill Metadata

Name
notion-sdk-patterns
Description
|

Notion SDK Patterns

Overview

Production-ready patterns for the official Notion SDK (@notionhq/client for TypeScript, notion-client for Python) covering client initialization, database queries with filters and sorts, cursor-based pagination, rich text construction, block manipulation, and type-safe error handling using SDK error codes.

The full workflow lives in three steps below. Each step shows the essential skeleton inline; deep variants (compound filters, generic pagination helpers, block manipulation, exhaustive error switches) are in references/patterns.md, and copy-paste task recipes are in references/examples.md.

Prerequisites

  • Node.js 18+ with @notionhq/client v2.x installed, or Python 3.9+ with notion-client
  • A Notion integration token (NOTION_TOKEN) from notion.so/my-integrations
  • Target databases/pages shared with the integration (Share > Invite > select your integration)
  • TypeScript 5+ with strict mode enabled (for TypeScript patterns)

Instructions

Step 1 — Initialize the Client and Query Databases

Set up the SDK client and execute a filtered, sorted database query.

TypeScript:

import { Client } from '@notionhq/client';

const notion = new Client({ auth: process.env.NOTION_TOKEN });

const response = await notion.databases.query({
  database_id,
  filter: {
    property: 'Status',
    select: { equals: 'Active' },
  },
  sorts: [{ property: 'Created', direction: 'descending' }],
});

Python:

from notion_client import Client

notion = Client(auth=os.environ["NOTION_TOKEN"])

results = notion.databases.query(
    database_id=db_id,
    filter={"property": "Status", "select": {"equals": "Active"}},
    sorts=[{"property": "Created", "direction": "descending"}],
)

For and/or compound filters and multi-key sorts, see the Compound Filters section of references/patterns.md.

Step 2 — Paginate Results and Manipulate Blocks

The Notion API returns at most 100 results per request. Loop on the cursor to retrieve every record:

let cursor: string | undefined;
do {
  const { results, next_cursor, has_more } = await notion.databases.query({
    database_id,
    start_cursor: cursor,
  });
  for (const page of results) {
    console.log(page.id);
  }
  cursor = has_more && next_cursor ? next_cursor : undefined;
} while (cursor);

A reusable generic collectPaginated helper, the Python pagination loop, and block read/append plus rich-text construction are in the Cursor-Based Pagination and Block Manipulation sections of references/patterns.md.

Step 3 — Handle Errors with SDK Error Codes

Use the SDK's built-in error type guards instead of catching generic exceptions:

import { isNotionClientError, APIErrorCode } from '@notionhq/client';

try {
  const page = await notion.pages.retrieve({ page_id: pageId });
} catch (error) {
  if (isNotionClientError(error)) {
    if (error.code === APIErrorCode.ObjectNotFound) {
      console.error('Page not found — ensure it is shared with the integration');
    } else {
      console.error(`Notion error [${error.code}]: ${error.message}`);
    }
  } else {
    throw error; // Re-throw non-Notion errors
  }
}

The exhaustive TypeScript switch over every error code, the Python APIResponseError handler, and a safeNotionCall Result-type wrapper are in the Error Handling section of references/patterns.md.

Output

Applying these patterns produces:

  • A configured SDK client connected via NOTION_TOKEN
  • Database queries with filters, sorts, and compound conditions
  • Complete result sets through cursor-based pagination (no missed records)
  • Block read/write operations with properly structured rich text
  • Exhaustive error handling using SDK error codes (not string matching)
  • TypeScript and Python implementations for cross-team consistency

Error Handling

| Error Code | Cause | Resolution | | --- | --- | --- | | ObjectNotFound | Page/database not shared with integration | Open in Notion > Share > Invite integration | | Unauthorized | Invalid or expired token | Regenerate at notion.so/my-integrations | | RateLimited | >3 requests/second sustained | Respect retry-after header; add exponential backoff | | ValidationError | Malformed filter, sort, or property | Check property names match database schema exactly | | ConflictError | Concurrent modification | Retry with fresh read; use optimistic concurrency | | RequestTimeout | Network or payload too large | Increase timeoutMs on client; reduce page_size |

The SDK has built-in retry with exponential backoff (defaults: maxRetries=2, initialRetryDelayMs=1000, maxRetryDelayMs=60000). Override via client constructor options. Full type-safe handlers for each code are in the Error Handling section of references/patterns.md.

Examples

Copy-paste recipes live in references/examples.md:

  • Property Value Extractors — type-safe getTitle/getSelect/getNumber/getCheckbox accessors that narrow each property's discriminated union.
  • Multi-Workspace Factory — cache one Client per workspace token for multi-tenant integrations.
  • Create a Page with Properties — populate title, select, date, and multi-select fields on pages.create.
  • Python Pagination — the equivalent cursor loop for notion-client.

Resources

Next Steps

  • Apply patterns in notion-core-workflow-a for end-to-end CRUD operations
  • See notion-data-handling for property type mapping and data transformation
  • See notion-rate-limits for advanced rate limiting strategies beyond built-in retry
  • See notion-common-errors for troubleshooting integration sharing and permission issues