Common Use Cases
This guide shows practical examples and workflows for common Notion SDK tasks.
Table of Contents
Section titled “Table of Contents”- Creating a Task Management Database
- Building a Documentation Page
- Querying and Filtering Databases
- Working with Rich Text
- Uploading Files and Images
- Working with Markdown Content
- Working with Views
- Managing Custom Emoji
- Managing Comments
- Batch Operations
- Pagination Patterns
- Syncing Data Between Systems
Creating a Task Management Database
Section titled “Creating a Task Management Database”Notion provides a canonical tasks schema. Pass database_type: 'tasks' to build a
database from it. The result matches a database of that type created in the Notion app. Use
initial_data_source instead when you need custom properties.
Using the Built-in Tasks Schema
Section titled “Using the Built-in Tasks Schema”The canonical tasks schema has these properties: Task name, Assignee, Status, and
Due. These are the English names. Property names follow the workspace’s language. The
example below assumes an English workspace. Retrieve the data source first to confirm exact
names in other languages.
import { Notion, parent, prop, sort } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Step 1: Create the database from Notion's canonical tasks schemaconst database = await notion.databases.create({ parent: { page_id: 'parent-page-id' }, database_type: 'tasks',});
// Step 2: Get data source for creating pagesconst dataSourceId = database.dataSources[0].id;
// Step 3: Add tasksconst tasks = [ { name: 'Review pull requests', dueDate: '2025-03-15' }, { name: 'Update documentation', dueDate: '2025-03-20' }, { name: 'Fix bug #123', dueDate: '2025-03-10' },];
for (const task of tasks) { await notion.pages.create({ parent: parent.dataSource(dataSourceId, database.id), properties: { 'Task name': prop.title(task.name), Due: prop.date(task.dueDate), }, });}
// Step 4: Query tasks sorted by due dateconst upcomingTasks = await notion.databases.query(database.id, { sorts: [sort.property('Due').ascending()],});
console.log(`${upcomingTasks.results.length} tasks found`);for (const task of upcomingTasks.results) { console.log(`- ${task.getTitle()}`);}Using Custom Properties
Section titled “Using Custom Properties”Provide initial_data_source instead of database_type when you need properties beyond the
canonical schema, for example a Priority select or a Tags multi-select. Provide exactly
one of database_type or initial_data_source.
import { Notion, parent, prop, filter, sort } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Step 1: Create the databaseconst database = await notion.databases.create({ parent: { page_id: 'parent-page-id' }, title: [{ type: 'text', text: { content: 'Task Manager' } }], initial_data_source: { properties: { Name: { title: {} }, Status: { status: { options: [ { name: 'To Do', color: 'red' }, { name: 'In Progress', color: 'yellow' }, { name: 'Done', color: 'green' }, ], }, }, Priority: { select: { options: [ { name: 'High', color: 'red' }, { name: 'Medium', color: 'yellow' }, { name: 'Low', color: 'gray' }, ], }, }, 'Due Date': { date: {} }, Assignee: { people: {} }, Tags: { multi_select: {} }, }, },});
// Step 2: Get data source for creating pagesconst dataSourceId = database.dataSources[0].id;
// Step 3: Add tasksconst tasks = [ { name: 'Review pull requests', status: 'In Progress', priority: 'High', dueDate: '2025-03-15', }, { name: 'Update documentation', status: 'To Do', priority: 'Medium', dueDate: '2025-03-20', }, { name: 'Fix bug #123', status: 'To Do', priority: 'High', dueDate: '2025-03-10', },];
for (const task of tasks) { await notion.pages.create({ parent: parent.dataSource(dataSourceId, database.id), properties: { Name: prop.title(task.name), Status: prop.status(task.status), Priority: prop.select(task.priority), 'Due Date': prop.date(task.dueDate), Tags: prop.multiSelect(['work', 'important']), }, });}
// Step 4: Query high-priority tasksconst highPriorityTasks = await notion.databases.query(database.id, { filter: filter.and( filter.select('Priority').equals('High'), filter.status('Status').doesNotEqual('Done'), ), sorts: [sort.property('Due Date').ascending()],});
console.log(`${highPriorityTasks.results.length} high-priority tasks found`);for (const task of highPriorityTasks.results) { console.log(`- ${task.getTitle()}`);}Building a Documentation Page
Section titled “Building a Documentation Page”Create a rich documentation page with various block types.
import { Notion, block, richText, icon, cover } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Step 1: Create the page with icon and coverconst page = await notion.pages.create({ parent: { page_id: 'parent-page-id' }, icon: icon.emoji('📚'), cover: cover.external('https://images.unsplash.com/photo-1516979187457-637abb4f9353'), properties: { title: { title: [{ type: 'text', text: { content: 'API Documentation' } }], }, },});
// Step 2: Add structured contentawait notion.blocks.children.append(page.id, { children: [ // Header with table of contents block.heading1('API Documentation'), block.tableOfContents(), block.divider(),
// Introduction block.heading2('Introduction'), block.paragraph( richText('Welcome to the API documentation. This guide covers ') .build() .concat(richText('authentication').bold().build()) .concat(richText(', ').build()) .concat(richText('endpoints').bold().build()) .concat(richText(', and ').build()) .concat(richText('examples').bold().build()) .concat(richText('.').build()), ), block.callout('This API requires authentication for all requests.', { icon: { type: 'emoji', emoji: '🔐' }, color: 'yellow_background', }),
// Authentication section block.heading2('Authentication', { isToggleable: true }), block.paragraph('All API requests require an API key in the Authorization header:'), block.code('Authorization: Bearer YOUR_API_KEY', 'bash'),
// Endpoints section block.heading2('Endpoints'),
block.heading3('GET /users'), block.paragraph('Retrieve a list of users.'), block.toggle('Example Request', { children: [ block.code( `curl -X GET https://api.example.com/users \\ -H "Authorization: Bearer YOUR_API_KEY"`, 'bash', ), ], }), block.toggle('Example Response', { children: [ block.code( JSON.stringify( { users: [ { id: '1', name: 'Alice', email: 'alice@example.com' }, { id: '2', name: 'Bob', email: 'bob@example.com' }, ], }, null, 2, ), 'json', ), ], }),
// Rate limits section block.heading2('Rate Limits'), block.bulletedListItem('100 requests per minute for authenticated users'), block.bulletedListItem('10 requests per minute for unauthenticated users'), block.bulletedListItem('Rate limit resets at the start of each minute'),
// Table with HTTP status codes block.heading2('HTTP Status Codes'), block.table(3, { hasColumnHeader: true, children: [ block.tableRow(['Code', 'Status', 'Description']), block.tableRow(['200', 'OK', 'Request succeeded']), block.tableRow(['401', 'Unauthorized', 'Invalid API key']), block.tableRow(['429', 'Too Many Requests', 'Rate limit exceeded']), block.tableRow(['500', 'Internal Server Error', 'Server error occurred']), ], }),
// Support section with columns block.heading2('Support'), block.columnList([ [block.heading3('Email'), block.paragraph('support@example.com')], [ block.heading3('Documentation'), block.paragraph(richText('Full docs').link('https://docs.example.com')), ], [ block.heading3('Status'), block.paragraph(richText('System status').link('https://status.example.com')), ], ]), ],});
console.log(`Documentation page created: ${page.url}`);Querying and Filtering Databases
Section titled “Querying and Filtering Databases”These examples show advanced database filtering and sorting.
import { Notion, filter, sort, paginate } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });const databaseId = 'your-database-id';
// Example 1: Filter by multiple conditionsconst activeHighPriorityTasks = await notion.databases.query(databaseId, { filter: filter.and( filter.status('Status').equals('In Progress'), filter.select('Priority').equals('High'), filter.date('Due Date').nextWeek(), ), sorts: [sort.property('Due Date').ascending()],});
// Example 2: Complex OR conditionsconst urgentOrOverdueTasks = await notion.databases.query(databaseId, { filter: filter.or( filter.select('Priority').equals('High'), filter.date('Due Date').before('2025-03-01'), filter.checkbox('Urgent').equals(true), ),});
// Example 3: Nested conditionsconst complexFilter = await notion.databases.query(databaseId, { filter: filter.and( filter.status('Status').doesNotEqual('Done'), filter.or(filter.select('Priority').equals('High'), filter.date('Due Date').nextWeek()), ),});
// Example 4: Text searchconst tasksWithKeyword = await notion.databases.query(databaseId, { filter: filter.text('Description').contains('urgent'),});
// Example 5: People and relation filtersconst myAssignedTasks = await notion.databases.query(databaseId, { filter: filter.and( filter.people('Assignee').contains('user-id'), filter.relation('Project').contains('project-page-id'), ),});
// Example 6: Empty and non-empty checksconst tasksWithoutDueDate = await notion.databases.query(databaseId, { filter: filter.date('Due Date').isEmpty(),});
// Example 7: Timestamp filtersconst recentlyEdited = await notion.databases.query(databaseId, { filter: filter.lastEditedTime().pastWeek(), sorts: [sort.lastEditedTime().descending()],});
// Example 8: Get all results with paginationconst allTasks = await paginate((cursor) => notion.databases.query(databaseId, { start_cursor: cursor, page_size: 100, filter: filter.status('Status').equals('In Progress'), }),);
console.log(`Total tasks: ${allTasks.length}`);Working with Rich Text
Section titled “Working with Rich Text”These examples show advanced rich text formatting and manipulation.
import { richText, RichText } from '@visus-io/notion-sdk-ts';import type { NotionColor } from '@visus-io/notion-sdk-ts';
// Example 1: Complex formatted textconst formattedText = richText.join( richText('Important: ').bold().color('red'), richText('This is a ').italic(), richText('critical').bold().italic().underline(), richText(' update about the '), richText('production').code(), richText(' environment.'),);
// Example 2: Text with multiple linksconst linksText = richText.join( richText('Check out our '), richText('documentation').link('https://docs.example.com').bold(), richText(' and '), richText('API reference').link('https://api.example.com').bold(), richText('.'),);
// Example 3: Mentions in textconst mentionText = richText.join( richText('Hey '), richText.mentionUser({ object: 'user', id: 'user-id' }), richText(', please review '), richText.mentionPage('page-id'), richText(' by '), richText.mentionDate('2025-03-15'), richText('.'),);
// Example 4: Equations in textconst mathText = richText.join( richText('The formula for kinetic energy is '), richText.equation('E = \\frac{1}{2}mv^2'), richText(' where m is mass and v is velocity.'),);
// Example 5: Parse existing rich textconst page = await notion.pages.retrieve('page-id');const nameProperty = page.properties.Name;const titleRichText = nameProperty.type === 'title' ? nameProperty.title : [];
const rt = new RichText(titleRichText);console.log('Plain text:', rt.toPlainText());console.log('Markdown:', rt.toMarkdown());console.log('HTML:', rt.toHTML());
if (rt.hasLinks()) { console.log('Links found:', rt.getLinks());}
// Example 6: Build dynamic rich textfunction createStatusMessage(status: string, username: string): any[] { const colors: Record<string, NotionColor> = { success: 'green', warning: 'yellow', error: 'red', };
return richText.join( richText(`[${status.toUpperCase()}]`) .bold() .color(colors[status] || 'default'), richText(` Task completed by ${username}`), );}
const message = createStatusMessage('success', 'Alice');Uploading Files and Images
Section titled “Uploading Files and Images”Upload files. Then use them in pages and databases.
import { Notion, icon, cover, block, notionFile } from '@visus-io/notion-sdk-ts';import { readFileSync } from 'fs';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Example 1: Upload an image and use as page coverconst imageUpload = await notion.fileUploads.uploadFile( 'banner.jpg', readFileSync('./banner.jpg'), 'image/jpeg',);
const page = await notion.pages.create({ parent: { page_id: 'parent-page-id' }, cover: cover.fileUpload(imageUpload.id), properties: { title: { title: [{ type: 'text', text: { content: 'My Page' } }], }, },});
// Example 2: Upload a PDF and add to pageconst pdfUpload = await notion.fileUploads.uploadFile( 'document.pdf', readFileSync('./document.pdf'), 'application/pdf',);
await notion.blocks.children.append(page.id, { children: [block.heading2('Attached Document'), block.pdf(notionFile.upload(pdfUpload.id))],});
// Example 3: Upload iconconst iconUpload = await notion.fileUploads.uploadFile( 'logo.png', readFileSync('./logo.png'), 'image/png',);
await notion.pages.update(page.id, { icon: icon.fileUpload(iconUpload.id),});
// Example 4: Multi-step upload with progress trackingconst fileData = readFileSync('./large-file.zip');
const initUpload = await notion.fileUploads.initiate({ filename: 'large-file.zip', content_type: 'application/zip', content_length: fileData.byteLength,});
console.log('Upload initiated:', initUpload.id);
await notion.fileUploads.upload(initUpload.uploadUrl, fileData, 'application/zip');
console.log('File uploaded, finalizing...');
const completed = await notion.fileUploads.complete(initUpload.completeUrl);console.log('Upload status:', completed.status);
// Example 5: Check upload statusconst status = await notion.fileUploads.retrieve(completed.id);if (status.isUploaded()) { console.log('File ready to use!');} else if (status.isFailed()) { console.error('Upload failed');}Working with Markdown Content
Section titled “Working with Markdown Content”pages.create() accepts a markdown string as an alternative to properties/children.
pages.getMarkdown() and pages.updateMarkdown() read and write that content directly, without
building a block tree by hand.
import { Notion, parent } from '@visus-io/notion-sdk-ts';import { readFileSync } from 'fs';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Example 1: Create a page from markdown instead of properties/children.// `markdown` is mutually exclusive with `properties` and `children`.const page = await notion.pages.create({ parent: parent.page('parent-page-id'), markdown: [ '# Release Notes', '', 'This release adds **markdown-based** page authoring.', '', '- Faster to write than a block tree', '- Round-trips through `getMarkdown()`/`updateMarkdown()`', ].join('\n'),});
// Example 2: Read a page's content back as markdownconst content = await notion.pages.getMarkdown(page.id);console.log(content.markdown);
if (content.truncated) { console.log('Content was truncated; fetch the block tree for the full page.');}
// Example 3: Find-and-replace an exact markdown substringawait notion.pages.updateMarkdown(page.id, { type: 'update_content', content_updates: [ { old_str: '# Release Notes', new_str: '# Release Notes (v3.1.0)', }, ],});
// Example 4: Replace the entire page bodyawait notion.pages.updateMarkdown(page.id, { type: 'replace_content', new_str: '# Rewritten\n\nThis page was replaced in one call.', allow_deleting_content: true,});
// Example 5: Large writes can process asynchronously. Discriminate the response// by `object`, then poll the async task through `notion.asyncTasks`.const largeMarkdown = readFileSync('./release-notes.md', 'utf8');const result = await notion.pages.updateMarkdown(page.id, { type: 'replace_content', new_str: largeMarkdown, allow_deleting_content: true, allow_async: true,});
if (result.object === 'async_task') { const task = await notion.asyncTasks.poll(result.id, { timeoutMs: 60_000 }); if (task.isSucceeded()) { console.log('Markdown update finished:', task.result); } else if (task.isFailed()) { console.error('Markdown update failed:', task.error); }} else { console.log('Markdown update applied synchronously:', result.markdown);}Working with Views
Section titled “Working with Views”Views control how a database or data source displays its rows: table, board, calendar, and
more. View queries are separate from dataSources.query() — they respect the view’s own filter,
sort, and layout, and each query result expires about 15 minutes after creation.
import { Notion } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });const dataSourceId = 'your-data-source-id';
// Example 1: List the views for a data sourceconst views = await notion.views.list({ data_source_id: dataSourceId });for (const view of views.results) { console.log(`${view.name} (${view.type})`);}
// Example 2: Create a board view grouped by statusconst boardView = await notion.views.create({ data_source_id: dataSourceId, name: 'By Status', type: 'board',});
// Example 3: Query a view's rows and check for the 10,000-result cap.// See the Pagination guide for how request_status signals truncation.const query = await notion.views.queries.create(boardView.id, { filter: { property: 'Status', status: { equals: 'In Progress' } },});
console.log(`${query.totalCount} rows, query expires at ${query.expiresAt}`);for (const page of query.results) { console.log(page.getTitle());}
if (query.requestStatus?.incomplete_reason === 'query_result_limit_reached') { console.log('Query hit the 10,000-result cap; narrow the filter to see the rest.');}
// Example 4: Clean up the query and the viewawait notion.views.queries.delete(boardView.id, query.id);await notion.views.delete(boardView.id);Managing Custom Emoji
Section titled “Managing Custom Emoji”List the custom emojis available in the workspace, then reuse one as a page or database icon.
import { Notion, icon } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Example 1: List all custom emojisconst emojis = await notion.customEmojis.list();for (const emoji of emojis.results) { console.log(`${emoji.name}: ${emoji.url}`);}
// Example 2: Look up one emoji by exact nameconst partyParrot = await notion.customEmojis.list({ name: 'party-parrot' });const emojiId = partyParrot.results[0]?.id;
// Example 3: Use a custom emoji as a page iconif (emojiId) { await notion.pages.update('page-id', { icon: icon.customEmoji(emojiId), });}Managing Comments
Section titled “Managing Comments”Add and retrieve comments on pages and blocks.
import { Notion, parent, richText, paginate } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Example 1: Add a comment to a pageawait notion.comments.create({ parent: parent.page('page-id'), rich_text: richText('This looks great! 🎉').build(),});
// Example 2: Add a comment with formatted textawait notion.comments.create({ parent: parent.page('page-id'), rich_text: richText.join( richText('Thanks for the update, '), richText.mentionUser({ object: 'user', id: 'user-id' }), richText('! Can you review '), richText.mentionPage('related-page-id'), richText('?'), ),});
// Example 3: Reply to a discussionconst existingComments = await notion.comments.list('page-id');const discussionId = existingComments.results[0].discussionId;
await notion.comments.create({ discussion_id: discussionId, rich_text: richText('I agree with this approach.').build(),});
// Example 4: Add comment with custom display nameawait notion.comments.create({ parent: parent.page('page-id'), rich_text: richText('Automated review complete ✓').build(), display_name: { type: 'custom', custom: { name: 'CI Bot' } },});
// Example 5: Get all comments on a pageconst allComments = await paginate((cursor) => notion.comments.list('page-id', { start_cursor: cursor }),);
console.log(`Total comments: ${allComments.length}`);for (const comment of allComments) { console.log(`${comment.getDisplayName()}: ${comment.getPlainText()}`);}
// Example 6: Add comment to a specific blockawait notion.comments.create({ parent: parent.block('block-id'), rich_text: richText('This section needs clarification.').build(),});
// Example 7: Comment with file attachments (requires uploaded file IDs)await notion.comments.create({ parent: parent.page('page-id'), rich_text: richText('Attaching the design mockups.').build(), attachments: [ { type: 'file_upload', file_upload_id: 'mockup-1-upload-id' }, { type: 'file_upload', file_upload_id: 'mockup-2-upload-id' }, ],});Batch Operations
Section titled “Batch Operations”These examples process multiple pages or blocks.
import { Notion, paginate, paginateIterator, prop } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Example 1: Batch update pages in a databaseconst databaseId = 'your-database-id';const pages = await paginate((cursor) => notion.databases.query(databaseId, { start_cursor: cursor }),);
console.log(`Updating ${pages.length} pages...`);
for (const page of pages) { await notion.pages.update(page.id, { properties: { 'Last Reviewed': prop.date(new Date().toISOString().split('T')[0]), }, });}
console.log('All pages updated!');
// Example 2: Memory-efficient iteration for large datasetsconsole.log('Processing pages one at a time...');let count = 0;
for await (const page of paginateIterator((cursor) => notion.databases.query(databaseId, { start_cursor: cursor }),)) { // Process each page without loading all into memory console.log(`Processing: ${page.getTitle()}`); count++;}
console.log(`Processed ${count} pages`);
// Example 3: Batch create pagesconst newTasks = [ { name: 'Task 1', priority: 'High' }, { name: 'Task 2', priority: 'Medium' }, { name: 'Task 3', priority: 'Low' },];
const database = await notion.databases.retrieve(databaseId);const dataSourceId = database.dataSources[0].id;
for (const task of newTasks) { await notion.pages.create({ parent: { data_source_id: dataSourceId, database_id: database.id }, properties: { Name: prop.title(task.name), Priority: prop.select(task.priority), }, });}
// Example 4: Batch trash completed tasksconst completedTasks = await paginate((cursor) => notion.databases.query(databaseId, { filter: { property: 'Status', status: { equals: 'Done' } }, start_cursor: cursor, }),);
console.log(`Trashing ${completedTasks.length} completed tasks...`);for (const task of completedTasks) { await notion.pages.trash(task.id);}Pagination Patterns
Section titled “Pagination Patterns”These examples show different strategies to handle paginated results.
import { Notion, paginate, paginateIterator, paginateWithMetadata } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
// Pattern 1: Get all results at onceconst allBlocks = await paginate((cursor) => notion.blocks.children.list('page-id', { start_cursor: cursor }),);console.log(`Total blocks: ${allBlocks.length}`);
// Pattern 2: Iterate one at a time (memory-efficient)for await (const block of paginateIterator((cursor) => notion.blocks.children.list('page-id', { start_cursor: cursor }),)) { if (block.isTextBlock()) { console.log(block.getPlainText()); }}
// Pattern 3: Get results with metadataconst { items, pageCount, totalCount } = await paginateWithMetadata((cursor) => notion.databases.query('database-id', { start_cursor: cursor }),);console.log(`Fetched ${totalCount} pages across ${pageCount} API calls`);
// Pattern 4: Manual pagination with controllet cursor: string | null = undefined;let allResults = [];
do { const response = await notion.databases.query('database-id', { start_cursor: cursor, page_size: 50, // Custom page size });
allResults.push(...response.results); cursor = response.next_cursor;
console.log(`Fetched ${response.results.length} results, has more: ${response.has_more}`);} while (cursor);
console.log(`Total results: ${allResults.length}`);Syncing Data Between Systems
Section titled “Syncing Data Between Systems”Sync data from external systems to Notion.
import { Notion, parent, prop, filter } from '@visus-io/notion-sdk-ts';
const notion = new Notion({ auth: process.env.NOTION_TOKEN });
interface ExternalTask { id: string; title: string; status: 'todo' | 'in_progress' | 'done'; assignee: string; dueDate: string;}
// Simulate fetching tasks from an external APIasync function fetchExternalTasks(): Promise<ExternalTask[]> { // In reality, this would call an external API return [ { id: 'ext-1', title: 'Fix login bug', status: 'in_progress', assignee: 'alice', dueDate: '2025-03-15', }, { id: 'ext-2', title: 'Update docs', status: 'todo', assignee: 'bob', dueDate: '2025-03-20' }, ];}
async function syncTasksToNotion(databaseId: string) { // Get database setup const database = await notion.databases.retrieve(databaseId); const dataSourceId = database.dataSources[0].id;
// Fetch external tasks const externalTasks = await fetchExternalTasks();
// Get existing tasks in Notion const notionPages = await notion.databases.query(databaseId); const existingTaskIds = notionPages.results.map((page) => { const idProp = page.properties['External ID']; return idProp?.type === 'rich_text' ? idProp.rich_text[0]?.plain_text : null; });
// Sync each external task for (const task of externalTasks) { const statusMap = { todo: 'To Do', in_progress: 'In Progress', done: 'Done', };
if (existingTaskIds.includes(task.id)) { // Update existing task const page = notionPages.results.find((p) => { const idProp = p.properties['External ID']; return idProp?.type === 'rich_text' && idProp.rich_text[0]?.plain_text === task.id; });
if (page) { await notion.pages.update(page.id, { properties: { Name: prop.title(task.title), Status: prop.status(statusMap[task.status]), 'Due Date': prop.date(task.dueDate), }, }); console.log(`Updated task: ${task.title}`); } } else { // Create new task await notion.pages.create({ parent: parent.dataSource(dataSourceId, databaseId), properties: { Name: prop.title(task.title), Status: prop.status(statusMap[task.status]), 'Due Date': prop.date(task.dueDate), 'External ID': prop.richText(task.id), }, }); console.log(`Created task: ${task.title}`); } }
console.log('Sync complete!');}
// Run syncawait syncTasksToNotion('your-database-id');Next Steps
Section titled “Next Steps”- Helpers: full details on helper functions.
- Models: full details on model objects.
- API Reference: complete endpoint documentation.
- Error Handling: how to handle errors.
- Pagination: advanced pagination techniques.