Corsair
PluginsNotion

Notion

Integrate Notion pages, databases, and workspace content

Quick Start

Install the plugin:

pnpm install @corsair-dev/notion

Add the Notion plugin to your Corsair instance:

corsair.ts
import { createCorsair } from "corsair";
import { notion } from "@corsair-dev/notion";

export const corsair = createCorsair({
    plugins: [
        notion(),
    ],
});

Once configured, you can work with Notion content:

// Create a page in a database
await corsair.notion.api.databasePages.createDatabasePage({
    parent: { database_id: "database-id-here" },
    properties: {
        Name: { title: [{ text: { content: "New Task" } }] },
    },
});

Authentication

Supported Auth Types

The Notion plugin supports:

  • api_key (default) - Use a Notion integration token

Default Auth Type

If no authType is specified, the plugin defaults to api_key.

Configuring API Key Authentication

Store credentials with the CLI:

pnpm corsair setup --notion api_key=your-integration-token

For webhook signature verification:

pnpm corsair setup --notion webhook_signature=your-webhook-secret

Alternatively, provide credentials directly in the config:

corsair.ts
notion({
    key: process.env.NOTION_TOKEN,
    webhookSecret: process.env.NOTION_WEBHOOK_SECRET,
})

See Authentication for details on managing credentials.

Options

OptionTypeDescription
authType'api_key'Authentication method (defaults to 'api_key')
keystringIntegration token (optional, uses database if not provided)
webhookSecretstringWebhook secret for x-notion-signature verification
hooksobjectEndpoint hooks for custom logic
webhookHooksobjectWebhook hooks for event handling
errorHandlersobjectCustom error handlers
permissionsobjectPermission configuration for AI agent access

Hooks

notion({
    hooks: {
        pages: {
            createPage: {
                before: async (ctx, input) => {
                    console.log("Creating page:", input.properties?.Name);
                    return { ctx, input };
                },
            },
        },
    },
})

See Hooks for complete documentation.

Error Handling

The plugin includes built-in error handlers for common scenarios. For complete documentation, see the Error Handlers reference.

Usage

Accessing the API

// Search pages
const pages = await corsair.notion.api.pages.searchPage({
    query: "Meeting Notes",
});

// Get a database
const database = await corsair.notion.api.databases.getDatabase({
    database_id: "database-id",
});

// Query database pages
const rows = await corsair.notion.api.databasePages.getManyDatabasePages({
    database_id: "database-id",
    filter: {
        property: "Status",
        select: { equals: "In Progress" },
    },
});

// Append blocks to a page
await corsair.notion.api.blocks.appendBlock({
    block_id: "page-id",
    children: [{
        type: "paragraph",
        paragraph: { rich_text: [{ text: { content: "Hello from Corsair!" } }] },
    }],
});

See API Endpoints for the complete reference.

Webhooks

Notion sends page lifecycle events to your webhook endpoint:

app/api/webhook/route.ts
import { processWebhook } from "corsair";
import { corsair } from "@/server/corsair";

export async function POST(request: Request) {
    const headers = Object.fromEntries(request.headers);
    const body = await request.json();

    const result = await processWebhook(corsair, headers, body);
    return result.response;
}

See Webhooks for all available events.

Database Access

const pages = await corsair.notion.db.pages.search({
    data: { title: "Meeting Notes" },
});

See Database for the complete schema.

Multi-Tenancy

const tenant = corsair.withTenant("workspace-123");

await tenant.notion.api.databasePages.createDatabasePage({
    parent: { database_id: "db-id" },
    properties: { Name: { title: [{ text: { content: "New Item" } }] } },
});

Examples

Example 1: Create a Task on New GitHub Issue

corsair.ts
import { inngest } from "./inngest";

export const corsair = createCorsair({
    plugins: [
        github({
            webhookHooks: {
                issues: {
                    opened: {
                        after: async (ctx, result) => {
                            await inngest.send({
                                name: "github/issue-opened",
                                data: {
                                    tenantId: ctx.tenantId,
                                    title: result.data.issue?.title,
                                    url: result.data.issue?.html_url,
                                    number: result.data.issue?.number,
                                },
                            });
                        },
                    },
                },
            },
        }),
        notion(),
    ],
});
inngest/functions.ts
export const createNotionTask = inngest.createFunction(
    { id: "create-notion-task-from-issue" },
    { event: "github/issue-opened" },
    async ({ event }) => {
        const tenant = corsair.withTenant(event.data.tenantId);

        await tenant.notion.api.databasePages.createDatabasePage({
            parent: { database_id: process.env.NOTION_TASKS_DB_ID! },
            properties: {
                Name: { title: [{ text: { content: event.data.title } }] }, 
                URL: { url: event.data.url }, 
                Status: { select: { name: "Todo" } },
            },
        });
    }
);

Example 2: Update Notion on Page Created Webhook

corsair.ts
export const corsair = createCorsair({
    plugins: [
        notion({
            webhookHooks: {
                databasePages: {
                    pageCreated: {
                        after: async (ctx, result) => {
                            await inngest.send({
                                name: "notion/page-created",
                                data: {
                                    tenantId: ctx.tenantId,
                                    pageId: result.data.id, 
                                    databaseId: result.data.parent?.database_id,
                                },
                            });
                        },
                    },
                },
            },
        }),
    ],
});
inngest/functions.ts
export const processNewPage = inngest.createFunction(
    { id: "process-new-notion-page" },
    { event: "notion/page-created" },
    async ({ event }) => {
        const tenant = corsair.withTenant(event.data.tenantId);

        await tenant.notion.api.blocks.appendBlock({
            block_id: event.data.pageId,
            children: [{
                type: "paragraph",
                paragraph: {
                    rich_text: [{ text: { content: "Auto-created by Corsair" } }], 
                },
            }],
        });
    }
);