chub-dev 0.1.0 → 0.1.2-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +55 -0
- package/bin/chub-mcp +2 -0
- package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
- package/dist/airtable/docs/database/python/DOC.md +1735 -0
- package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
- package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
- package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
- package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
- package/dist/asana/docs/tasks/DOC.md +1396 -0
- package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
- package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
- package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
- package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
- package/dist/auth0/docs/identity/python/DOC.md +1199 -0
- package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
- package/dist/aws/docs/s3/python/DOC.md +1807 -0
- package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
- package/dist/binance/docs/trading/python/DOC.md +1454 -0
- package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
- package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
- package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
- package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
- package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
- package/dist/clerk/docs/auth/python/DOC.md +274 -0
- package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
- package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
- package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
- package/dist/cohere/docs/llm/DOC.md +1335 -0
- package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
- package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
- package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
- package/dist/deepgram/docs/speech/python/DOC.md +685 -0
- package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
- package/dist/deepl/docs/translation/python/DOC.md +944 -0
- package/dist/deepseek/docs/llm/DOC.md +1220 -0
- package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
- package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
- package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
- package/dist/discord/docs/bot/python/DOC.md +1130 -0
- package/dist/elasticsearch/docs/search/DOC.md +1634 -0
- package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
- package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
- package/dist/firebase/docs/auth/DOC.md +1015 -0
- package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
- package/dist/gemini/docs/genai/python/DOC.md +555 -0
- package/dist/github/docs/octokit/DOC.md +1560 -0
- package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
- package/dist/google/docs/bigquery/python/DOC.md +1503 -0
- package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
- package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
- package/dist/huggingface/docs/transformers/DOC.md +948 -0
- package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
- package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
- package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
- package/dist/jira/docs/issues/python/DOC.md +1492 -0
- package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
- package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
- package/dist/landingai-ade/docs/api/DOC.md +620 -0
- package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
- package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
- package/dist/landingai-ade/skills/SKILL.md +489 -0
- package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
- package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
- package/dist/linear/docs/tracker/DOC.md +1554 -0
- package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
- package/dist/livekit/docs/realtime/python/DOC.md +163 -0
- package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
- package/dist/meilisearch/docs/search/DOC.md +1241 -0
- package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
- package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
- package/dist/mongodb/docs/atlas/DOC.md +2041 -0
- package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
- package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
- package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
- package/dist/okta/docs/identity/python/DOC.md +1401 -0
- package/dist/openai/docs/chat/javascript/DOC.md +407 -0
- package/dist/openai/docs/chat/python/DOC.md +568 -0
- package/dist/paypal/docs/checkout/DOC.md +278 -0
- package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
- package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
- package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
- package/dist/plaid/docs/banking/python/DOC.md +1203 -0
- package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
- package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
- package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
- package/dist/prisma/docs/orm/python/DOC.md +1317 -0
- package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
- package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
- package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
- package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
- package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
- package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
- package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
- package/dist/redis/docs/key-value/python/DOC.md +2054 -0
- package/dist/registry.json +2817 -0
- package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
- package/dist/resend/docs/email/DOC.md +1271 -0
- package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
- package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
- package/dist/search-index.json +1 -0
- package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
- package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
- package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
- package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
- package/dist/shopify/docs/storefront/DOC.md +457 -0
- package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
- package/dist/slack/docs/workspace/python/DOC.md +271 -0
- package/dist/square/docs/payments/javascript/DOC.md +1855 -0
- package/dist/square/docs/payments/python/DOC.md +1728 -0
- package/dist/stripe/docs/api/DOC.md +1727 -0
- package/dist/stripe/docs/payments/DOC.md +1726 -0
- package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
- package/dist/stytch/docs/auth/python/DOC.md +1962 -0
- package/dist/supabase/docs/client/DOC.md +1606 -0
- package/dist/twilio/docs/messaging/python/DOC.md +469 -0
- package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
- package/dist/vercel/docs/platform/DOC.md +1940 -0
- package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
- package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
- package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
- package/dist/zendesk/docs/support/python/DOC.md +2297 -0
- package/package.json +22 -6
- package/skills/get-api-docs/SKILL.md +84 -0
- package/src/commands/annotate.js +83 -0
- package/src/commands/build.js +12 -1
- package/src/commands/feedback.js +150 -0
- package/src/commands/get.js +83 -42
- package/src/commands/search.js +7 -0
- package/src/index.js +43 -17
- package/src/lib/analytics.js +90 -0
- package/src/lib/annotations.js +57 -0
- package/src/lib/bm25.js +170 -0
- package/src/lib/cache.js +69 -6
- package/src/lib/config.js +8 -3
- package/src/lib/identity.js +99 -0
- package/src/lib/registry.js +103 -20
- package/src/lib/telemetry.js +86 -0
- package/src/mcp/server.js +177 -0
- package/src/mcp/tools.js +251 -0
|
@@ -0,0 +1,1435 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workspace-api
|
|
3
|
+
description: "Notion JavaScript/TypeScript SDK for interacting with Notion workspaces, pages, and databases via the official API."
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "javascript"
|
|
6
|
+
versions: "5.3.0"
|
|
7
|
+
updated-on: "2026-03-01"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "notion,api,workspace,pages,databases"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Notion API JavaScript/TypeScript SDK Coding Guidelines
|
|
13
|
+
|
|
14
|
+
You are a Notion API coding expert. Help me with writing code using the Notion API calling the official libraries and SDKs.
|
|
15
|
+
|
|
16
|
+
You can find the official SDK documentation and code samples here:
|
|
17
|
+
https://developers.notion.com/reference/
|
|
18
|
+
|
|
19
|
+
## Golden Rule: Use the Correct and Current SDK
|
|
20
|
+
|
|
21
|
+
Always use the Notion JavaScript SDK to interact with Notion workspaces, which is the standard library for all Notion API interactions. Do not use legacy libraries or unofficial SDKs.
|
|
22
|
+
|
|
23
|
+
- **Library Name:** Notion JavaScript SDK
|
|
24
|
+
- **NPM Package:** `@notionhq/client`
|
|
25
|
+
- **Legacy Libraries**: `notion-api-js`, `notion-client`, and other unofficial packages are not recommended
|
|
26
|
+
|
|
27
|
+
**Installation:**
|
|
28
|
+
|
|
29
|
+
- **Correct:** `npm install @notionhq/client`
|
|
30
|
+
|
|
31
|
+
**APIs and Usage:**
|
|
32
|
+
|
|
33
|
+
- **Correct:** `const { Client } = require("@notionhq/client")`
|
|
34
|
+
- **Correct:** `const notion = new Client({ auth: process.env.NOTION_TOKEN })`
|
|
35
|
+
- **Correct:** `await notion.pages.create(...)`
|
|
36
|
+
- **Correct:** `await notion.databases.query(...)`
|
|
37
|
+
- **Correct:** `await notion.dataSources.query(...)`
|
|
38
|
+
- **Incorrect:** `NotionClient` or `NotionAPI`
|
|
39
|
+
- **Incorrect:** Legacy notion-py style APIs
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
Install the Notion JavaScript SDK using npm:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @notionhq/client
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Set your environment variable for the Notion API token:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
export NOTION_TOKEN="your_integration_token_here"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
You can obtain an integration token by creating a new integration at:
|
|
56
|
+
https://www.notion.com/my-integrations
|
|
57
|
+
|
|
58
|
+
## Initialization and API Key
|
|
59
|
+
|
|
60
|
+
The `@notionhq/client` library requires creating a `Client` instance for all API calls.
|
|
61
|
+
|
|
62
|
+
- Always use `const notion = new Client({})` to create an instance.
|
|
63
|
+
- Set the `NOTION_TOKEN` environment variable, which will be picked up automatically.
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
const { Client } = require('@notionhq/client');
|
|
67
|
+
|
|
68
|
+
// Uses the NOTION_TOKEN environment variable if auth not specified
|
|
69
|
+
const notion = new Client({
|
|
70
|
+
auth: process.env.NOTION_TOKEN,
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Client Configuration Options
|
|
75
|
+
|
|
76
|
+
```javascript
|
|
77
|
+
const { Client, LogLevel } = require('@notionhq/client');
|
|
78
|
+
|
|
79
|
+
const notion = new Client({
|
|
80
|
+
auth: process.env.NOTION_TOKEN,
|
|
81
|
+
logLevel: LogLevel.DEBUG, // Controls logging verbosity (default: LogLevel.WARN)
|
|
82
|
+
timeoutMs: 60000, // Request timeout in milliseconds (default: 60000)
|
|
83
|
+
baseUrl: 'https://api.notion.com', // API endpoint (default shown)
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Important API Version Changes (2025-09-03)
|
|
88
|
+
|
|
89
|
+
As of API version 2025-09-03, Notion separated databases and data sources:
|
|
90
|
+
|
|
91
|
+
- **Databases** parent one or more data sources
|
|
92
|
+
- **Data Sources** each parent zero or more pages
|
|
93
|
+
- Use `notion.dataSources.query()` instead of `notion.databases.query()` for newer implementations
|
|
94
|
+
- The SDK minimum version for this API is v5.0.0+
|
|
95
|
+
|
|
96
|
+
## Pages API
|
|
97
|
+
|
|
98
|
+
### Create a Page
|
|
99
|
+
|
|
100
|
+
Create a new page as a child of an existing page:
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
const { Client } = require('@notionhq/client');
|
|
104
|
+
const notion = new Client({ auth: process.env.NOTION_TOKEN });
|
|
105
|
+
|
|
106
|
+
async function createPage() {
|
|
107
|
+
const response = await notion.pages.create({
|
|
108
|
+
parent: {
|
|
109
|
+
page_id: '494c87d072c44cf6960f55f8427f7692',
|
|
110
|
+
},
|
|
111
|
+
properties: {
|
|
112
|
+
title: {
|
|
113
|
+
type: 'title',
|
|
114
|
+
title: [
|
|
115
|
+
{
|
|
116
|
+
type: 'text',
|
|
117
|
+
text: { content: 'A note from your pals at Notion' },
|
|
118
|
+
},
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
console.log(response);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
createPage();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Create a Page in a Data Source (Database)
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
async function createPageInDataSource() {
|
|
134
|
+
const response = await notion.pages.create({
|
|
135
|
+
parent: {
|
|
136
|
+
data_source_id: '897e5a76-ae52-4b48-9fdf-e71f5945d1af',
|
|
137
|
+
},
|
|
138
|
+
properties: {
|
|
139
|
+
// Properties must match your data source schema
|
|
140
|
+
Name: {
|
|
141
|
+
title: [
|
|
142
|
+
{
|
|
143
|
+
text: {
|
|
144
|
+
content: 'Golden Gate Bridge',
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
],
|
|
148
|
+
},
|
|
149
|
+
Tags: {
|
|
150
|
+
multi_select: [
|
|
151
|
+
{ name: 'Landmark' },
|
|
152
|
+
{ name: 'San Francisco' },
|
|
153
|
+
],
|
|
154
|
+
},
|
|
155
|
+
Status: {
|
|
156
|
+
status: {
|
|
157
|
+
name: 'Active',
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
return response;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Create a Page with Content Blocks
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
async function createPageWithContent() {
|
|
171
|
+
const response = await notion.pages.create({
|
|
172
|
+
parent: {
|
|
173
|
+
page_id: '494c87d072c44cf6960f55f8427f7692',
|
|
174
|
+
},
|
|
175
|
+
properties: {
|
|
176
|
+
title: {
|
|
177
|
+
title: [{ text: { content: 'My New Page' } }],
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
children: [
|
|
181
|
+
{
|
|
182
|
+
object: 'block',
|
|
183
|
+
type: 'heading_2',
|
|
184
|
+
heading_2: {
|
|
185
|
+
rich_text: [{ type: 'text', text: { content: 'Introduction' } }],
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
object: 'block',
|
|
190
|
+
type: 'paragraph',
|
|
191
|
+
paragraph: {
|
|
192
|
+
rich_text: [
|
|
193
|
+
{
|
|
194
|
+
type: 'text',
|
|
195
|
+
text: { content: 'This is a paragraph with ' },
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
type: 'text',
|
|
199
|
+
text: { content: 'bold text', link: null },
|
|
200
|
+
annotations: { bold: true },
|
|
201
|
+
},
|
|
202
|
+
],
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
object: 'block',
|
|
207
|
+
type: 'bulleted_list_item',
|
|
208
|
+
bulleted_list_item: {
|
|
209
|
+
rich_text: [{ type: 'text', text: { content: 'First bullet point' } }],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
return response;
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Retrieve a Page
|
|
220
|
+
|
|
221
|
+
```javascript
|
|
222
|
+
async function retrievePage(pageId) {
|
|
223
|
+
const response = await notion.pages.retrieve({
|
|
224
|
+
page_id: pageId,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
console.log('Page title:', response.properties.title);
|
|
228
|
+
console.log('Created at:', response.created_time);
|
|
229
|
+
console.log('Last edited:', response.last_edited_time);
|
|
230
|
+
|
|
231
|
+
return response;
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### Update Page Properties
|
|
236
|
+
|
|
237
|
+
```javascript
|
|
238
|
+
async function updatePage(pageId) {
|
|
239
|
+
const response = await notion.pages.update({
|
|
240
|
+
page_id: pageId,
|
|
241
|
+
properties: {
|
|
242
|
+
Status: {
|
|
243
|
+
status: {
|
|
244
|
+
name: 'Completed',
|
|
245
|
+
},
|
|
246
|
+
},
|
|
247
|
+
Tags: {
|
|
248
|
+
multi_select: [
|
|
249
|
+
{ name: 'Updated' },
|
|
250
|
+
{ name: 'Important' },
|
|
251
|
+
],
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
return response;
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### Archive (Trash) a Page
|
|
261
|
+
|
|
262
|
+
```javascript
|
|
263
|
+
async function archivePage(pageId) {
|
|
264
|
+
const response = await notion.pages.update({
|
|
265
|
+
page_id: pageId,
|
|
266
|
+
archived: true,
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
return response;
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Databases API
|
|
274
|
+
|
|
275
|
+
### Query a Database (Legacy - Pre 2025-09-03)
|
|
276
|
+
|
|
277
|
+
```javascript
|
|
278
|
+
async function queryDatabase(databaseId) {
|
|
279
|
+
const response = await notion.databases.query({
|
|
280
|
+
database_id: databaseId,
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
console.log('Results:', response.results);
|
|
284
|
+
return response;
|
|
285
|
+
}
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Query with Filters and Sorting
|
|
289
|
+
|
|
290
|
+
```javascript
|
|
291
|
+
async function queryDatabaseWithFilters(databaseId) {
|
|
292
|
+
const response = await notion.databases.query({
|
|
293
|
+
database_id: databaseId,
|
|
294
|
+
filter: {
|
|
295
|
+
and: [
|
|
296
|
+
{
|
|
297
|
+
property: 'Status',
|
|
298
|
+
status: {
|
|
299
|
+
equals: 'Active',
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
property: 'Priority',
|
|
304
|
+
select: {
|
|
305
|
+
equals: 'High',
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
},
|
|
310
|
+
sorts: [
|
|
311
|
+
{
|
|
312
|
+
property: 'Created',
|
|
313
|
+
direction: 'descending',
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
return response;
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Query Data Source (API Version 2025-09-03+)
|
|
323
|
+
|
|
324
|
+
```javascript
|
|
325
|
+
async function queryDataSource(dataSourceId) {
|
|
326
|
+
const response = await notion.dataSources.query({
|
|
327
|
+
data_source_id: dataSourceId,
|
|
328
|
+
filter: {
|
|
329
|
+
property: 'Landmark',
|
|
330
|
+
rich_text: {
|
|
331
|
+
contains: 'Bridge',
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
return response;
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### Filter Examples
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
// Text property contains value
|
|
344
|
+
const textFilter = {
|
|
345
|
+
property: 'Description',
|
|
346
|
+
rich_text: { contains: 'important' },
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
// Checkbox equals value
|
|
350
|
+
const checkboxFilter = {
|
|
351
|
+
property: 'Done',
|
|
352
|
+
checkbox: { equals: true },
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// Date is after specific date
|
|
356
|
+
const dateFilter = {
|
|
357
|
+
property: 'Due Date',
|
|
358
|
+
date: { after: '2025-01-01' },
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// Number greater than value
|
|
362
|
+
const numberFilter = {
|
|
363
|
+
property: 'Score',
|
|
364
|
+
number: { greater_than: 50 },
|
|
365
|
+
};
|
|
366
|
+
|
|
367
|
+
// Multi-select contains value
|
|
368
|
+
const multiSelectFilter = {
|
|
369
|
+
property: 'Tags',
|
|
370
|
+
multi_select: { contains: 'urgent' },
|
|
371
|
+
};
|
|
372
|
+
|
|
373
|
+
// Compound OR filter
|
|
374
|
+
const orFilter = {
|
|
375
|
+
or: [
|
|
376
|
+
{ property: 'Tags', multi_select: { contains: 'A' } },
|
|
377
|
+
{ property: 'Tags', multi_select: { contains: 'B' } },
|
|
378
|
+
],
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// Compound AND filter
|
|
382
|
+
const andFilter = {
|
|
383
|
+
and: [
|
|
384
|
+
{ property: 'Done', checkbox: { equals: false } },
|
|
385
|
+
{ property: 'Priority', select: { equals: 'High' } },
|
|
386
|
+
],
|
|
387
|
+
};
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Retrieve a Database
|
|
391
|
+
|
|
392
|
+
```javascript
|
|
393
|
+
async function retrieveDatabase(databaseId) {
|
|
394
|
+
const response = await notion.databases.retrieve({
|
|
395
|
+
database_id: databaseId,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
console.log('Database title:', response.title);
|
|
399
|
+
console.log('Properties:', response.properties);
|
|
400
|
+
|
|
401
|
+
return response;
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Create a Database
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
async function createDatabase(parentPageId) {
|
|
409
|
+
const response = await notion.databases.create({
|
|
410
|
+
parent: {
|
|
411
|
+
type: 'page_id',
|
|
412
|
+
page_id: parentPageId,
|
|
413
|
+
},
|
|
414
|
+
title: [
|
|
415
|
+
{
|
|
416
|
+
type: 'text',
|
|
417
|
+
text: {
|
|
418
|
+
content: 'Task List',
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
],
|
|
422
|
+
properties: {
|
|
423
|
+
Name: {
|
|
424
|
+
title: {},
|
|
425
|
+
},
|
|
426
|
+
Status: {
|
|
427
|
+
status: {
|
|
428
|
+
options: [
|
|
429
|
+
{ name: 'Not started', color: 'red' },
|
|
430
|
+
{ name: 'In progress', color: 'yellow' },
|
|
431
|
+
{ name: 'Completed', color: 'green' },
|
|
432
|
+
],
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
Priority: {
|
|
436
|
+
select: {
|
|
437
|
+
options: [
|
|
438
|
+
{ name: 'High', color: 'red' },
|
|
439
|
+
{ name: 'Medium', color: 'yellow' },
|
|
440
|
+
{ name: 'Low', color: 'gray' },
|
|
441
|
+
],
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
Tags: {
|
|
445
|
+
multi_select: {
|
|
446
|
+
options: [
|
|
447
|
+
{ name: 'Bug', color: 'red' },
|
|
448
|
+
{ name: 'Feature', color: 'blue' },
|
|
449
|
+
],
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
'Due Date': {
|
|
453
|
+
date: {},
|
|
454
|
+
},
|
|
455
|
+
},
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
return response;
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Update Database Properties
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
async function updateDatabase(databaseId) {
|
|
466
|
+
const response = await notion.databases.update({
|
|
467
|
+
database_id: databaseId,
|
|
468
|
+
title: [
|
|
469
|
+
{
|
|
470
|
+
text: {
|
|
471
|
+
content: 'Updated Task List',
|
|
472
|
+
},
|
|
473
|
+
},
|
|
474
|
+
],
|
|
475
|
+
properties: {
|
|
476
|
+
Status: {
|
|
477
|
+
status: {
|
|
478
|
+
options: [
|
|
479
|
+
{ name: 'To Do', color: 'red' },
|
|
480
|
+
{ name: 'Doing', color: 'yellow' },
|
|
481
|
+
{ name: 'Done', color: 'green' },
|
|
482
|
+
],
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
return response;
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
## Blocks API
|
|
493
|
+
|
|
494
|
+
### Retrieve Block Children
|
|
495
|
+
|
|
496
|
+
```javascript
|
|
497
|
+
async function getBlockChildren(blockId) {
|
|
498
|
+
const response = await notion.blocks.children.list({
|
|
499
|
+
block_id: blockId,
|
|
500
|
+
page_size: 50,
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
console.log('Number of blocks:', response.results.length);
|
|
504
|
+
return response.results;
|
|
505
|
+
}
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
### Append Block Children
|
|
509
|
+
|
|
510
|
+
```javascript
|
|
511
|
+
async function appendBlockChildren(blockId) {
|
|
512
|
+
const response = await notion.blocks.children.append({
|
|
513
|
+
block_id: blockId,
|
|
514
|
+
children: [
|
|
515
|
+
{
|
|
516
|
+
object: 'block',
|
|
517
|
+
type: 'heading_2',
|
|
518
|
+
heading_2: {
|
|
519
|
+
rich_text: [
|
|
520
|
+
{
|
|
521
|
+
type: 'text',
|
|
522
|
+
text: { content: 'New Section' },
|
|
523
|
+
},
|
|
524
|
+
],
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
object: 'block',
|
|
529
|
+
type: 'paragraph',
|
|
530
|
+
paragraph: {
|
|
531
|
+
rich_text: [
|
|
532
|
+
{
|
|
533
|
+
type: 'text',
|
|
534
|
+
text: { content: 'This is a new paragraph.' },
|
|
535
|
+
},
|
|
536
|
+
],
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
object: 'block',
|
|
541
|
+
type: 'to_do',
|
|
542
|
+
to_do: {
|
|
543
|
+
rich_text: [{ type: 'text', text: { content: 'Complete this task' } }],
|
|
544
|
+
checked: false,
|
|
545
|
+
},
|
|
546
|
+
},
|
|
547
|
+
],
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
return response;
|
|
551
|
+
}
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Common Block Types
|
|
555
|
+
|
|
556
|
+
```javascript
|
|
557
|
+
// Heading blocks
|
|
558
|
+
const heading1 = {
|
|
559
|
+
type: 'heading_1',
|
|
560
|
+
heading_1: {
|
|
561
|
+
rich_text: [{ text: { content: 'Heading 1' } }],
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
const heading2 = {
|
|
566
|
+
type: 'heading_2',
|
|
567
|
+
heading_2: {
|
|
568
|
+
rich_text: [{ text: { content: 'Heading 2' } }],
|
|
569
|
+
},
|
|
570
|
+
};
|
|
571
|
+
|
|
572
|
+
const heading3 = {
|
|
573
|
+
type: 'heading_3',
|
|
574
|
+
heading_3: {
|
|
575
|
+
rich_text: [{ text: { content: 'Heading 3' } }],
|
|
576
|
+
},
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
// Paragraph with formatting
|
|
580
|
+
const paragraph = {
|
|
581
|
+
type: 'paragraph',
|
|
582
|
+
paragraph: {
|
|
583
|
+
rich_text: [
|
|
584
|
+
{ text: { content: 'Normal text ' } },
|
|
585
|
+
{ text: { content: 'bold' }, annotations: { bold: true } },
|
|
586
|
+
{ text: { content: ' and ' } },
|
|
587
|
+
{ text: { content: 'italic' }, annotations: { italic: true } },
|
|
588
|
+
{ text: { content: ' and ' } },
|
|
589
|
+
{ text: { content: 'code' }, annotations: { code: true } },
|
|
590
|
+
],
|
|
591
|
+
},
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
// Bulleted list item
|
|
595
|
+
const bulletedListItem = {
|
|
596
|
+
type: 'bulleted_list_item',
|
|
597
|
+
bulleted_list_item: {
|
|
598
|
+
rich_text: [{ text: { content: 'Bullet point' } }],
|
|
599
|
+
},
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
// Numbered list item
|
|
603
|
+
const numberedListItem = {
|
|
604
|
+
type: 'numbered_list_item',
|
|
605
|
+
numbered_list_item: {
|
|
606
|
+
rich_text: [{ text: { content: 'Numbered item' } }],
|
|
607
|
+
},
|
|
608
|
+
};
|
|
609
|
+
|
|
610
|
+
// To-do item
|
|
611
|
+
const toDo = {
|
|
612
|
+
type: 'to_do',
|
|
613
|
+
to_do: {
|
|
614
|
+
rich_text: [{ text: { content: 'Task to complete' } }],
|
|
615
|
+
checked: false,
|
|
616
|
+
},
|
|
617
|
+
};
|
|
618
|
+
|
|
619
|
+
// Toggle block (collapsible)
|
|
620
|
+
const toggle = {
|
|
621
|
+
type: 'toggle',
|
|
622
|
+
toggle: {
|
|
623
|
+
rich_text: [{ text: { content: 'Click to expand' } }],
|
|
624
|
+
},
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
// Quote
|
|
628
|
+
const quote = {
|
|
629
|
+
type: 'quote',
|
|
630
|
+
quote: {
|
|
631
|
+
rich_text: [{ text: { content: 'This is a quote' } }],
|
|
632
|
+
},
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
// Callout
|
|
636
|
+
const callout = {
|
|
637
|
+
type: 'callout',
|
|
638
|
+
callout: {
|
|
639
|
+
rich_text: [{ text: { content: 'Important note' } }],
|
|
640
|
+
icon: { emoji: '💡' },
|
|
641
|
+
},
|
|
642
|
+
};
|
|
643
|
+
|
|
644
|
+
// Code block
|
|
645
|
+
const codeBlock = {
|
|
646
|
+
type: 'code',
|
|
647
|
+
code: {
|
|
648
|
+
rich_text: [{ text: { content: 'const x = 42;' } }],
|
|
649
|
+
language: 'javascript',
|
|
650
|
+
},
|
|
651
|
+
};
|
|
652
|
+
|
|
653
|
+
// Divider
|
|
654
|
+
const divider = {
|
|
655
|
+
type: 'divider',
|
|
656
|
+
divider: {},
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
// Image
|
|
660
|
+
const image = {
|
|
661
|
+
type: 'image',
|
|
662
|
+
image: {
|
|
663
|
+
type: 'external',
|
|
664
|
+
external: {
|
|
665
|
+
url: 'https://example.com/image.png',
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
// Bookmark
|
|
671
|
+
const bookmark = {
|
|
672
|
+
type: 'bookmark',
|
|
673
|
+
bookmark: {
|
|
674
|
+
url: 'https://notion.so',
|
|
675
|
+
},
|
|
676
|
+
};
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### Update a Block
|
|
680
|
+
|
|
681
|
+
```javascript
|
|
682
|
+
async function updateBlock(blockId) {
|
|
683
|
+
const response = await notion.blocks.update({
|
|
684
|
+
block_id: blockId,
|
|
685
|
+
paragraph: {
|
|
686
|
+
rich_text: [
|
|
687
|
+
{
|
|
688
|
+
text: {
|
|
689
|
+
content: 'Updated paragraph content',
|
|
690
|
+
},
|
|
691
|
+
},
|
|
692
|
+
],
|
|
693
|
+
},
|
|
694
|
+
});
|
|
695
|
+
|
|
696
|
+
return response;
|
|
697
|
+
}
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
### Delete a Block
|
|
701
|
+
|
|
702
|
+
```javascript
|
|
703
|
+
async function deleteBlock(blockId) {
|
|
704
|
+
const response = await notion.blocks.delete({
|
|
705
|
+
block_id: blockId,
|
|
706
|
+
});
|
|
707
|
+
|
|
708
|
+
return response;
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
### Retrieve a Block
|
|
713
|
+
|
|
714
|
+
```javascript
|
|
715
|
+
async function retrieveBlock(blockId) {
|
|
716
|
+
const response = await notion.blocks.retrieve({
|
|
717
|
+
block_id: blockId,
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
console.log('Block type:', response.type);
|
|
721
|
+
return response;
|
|
722
|
+
}
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
## Users API
|
|
726
|
+
|
|
727
|
+
### List All Users
|
|
728
|
+
|
|
729
|
+
```javascript
|
|
730
|
+
async function listUsers() {
|
|
731
|
+
const response = await notion.users.list({});
|
|
732
|
+
|
|
733
|
+
console.log('Users:', response.results);
|
|
734
|
+
return response.results;
|
|
735
|
+
}
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
### Retrieve a User
|
|
739
|
+
|
|
740
|
+
```javascript
|
|
741
|
+
async function retrieveUser(userId) {
|
|
742
|
+
const response = await notion.users.retrieve({
|
|
743
|
+
user_id: userId,
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
console.log('User name:', response.name);
|
|
747
|
+
console.log('User type:', response.type);
|
|
748
|
+
|
|
749
|
+
return response;
|
|
750
|
+
}
|
|
751
|
+
```
|
|
752
|
+
|
|
753
|
+
### Retrieve Bot User (Your Integration)
|
|
754
|
+
|
|
755
|
+
```javascript
|
|
756
|
+
async function retrieveBotUser() {
|
|
757
|
+
const response = await notion.users.me();
|
|
758
|
+
|
|
759
|
+
console.log('Bot name:', response.name);
|
|
760
|
+
console.log('Bot ID:', response.id);
|
|
761
|
+
|
|
762
|
+
return response;
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
## Search API
|
|
767
|
+
|
|
768
|
+
### Basic Search
|
|
769
|
+
|
|
770
|
+
```javascript
|
|
771
|
+
async function searchPages(query) {
|
|
772
|
+
const response = await notion.search({
|
|
773
|
+
query: query,
|
|
774
|
+
filter: {
|
|
775
|
+
value: 'page',
|
|
776
|
+
property: 'object',
|
|
777
|
+
},
|
|
778
|
+
sort: {
|
|
779
|
+
direction: 'descending',
|
|
780
|
+
timestamp: 'last_edited_time',
|
|
781
|
+
},
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
return response.results;
|
|
785
|
+
}
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
### Search for Databases
|
|
789
|
+
|
|
790
|
+
```javascript
|
|
791
|
+
async function searchDatabases(query) {
|
|
792
|
+
const response = await notion.search({
|
|
793
|
+
query: query,
|
|
794
|
+
filter: {
|
|
795
|
+
value: 'database',
|
|
796
|
+
property: 'object',
|
|
797
|
+
},
|
|
798
|
+
});
|
|
799
|
+
|
|
800
|
+
return response.results;
|
|
801
|
+
}
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
### Search All Content
|
|
805
|
+
|
|
806
|
+
```javascript
|
|
807
|
+
async function searchAll(query) {
|
|
808
|
+
const response = await notion.search({
|
|
809
|
+
query: query,
|
|
810
|
+
page_size: 100,
|
|
811
|
+
});
|
|
812
|
+
|
|
813
|
+
console.log(`Found ${response.results.length} results`);
|
|
814
|
+
return response.results;
|
|
815
|
+
}
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
## Comments API
|
|
819
|
+
|
|
820
|
+
### Create a Comment
|
|
821
|
+
|
|
822
|
+
```javascript
|
|
823
|
+
async function createComment(pageId) {
|
|
824
|
+
const response = await notion.comments.create({
|
|
825
|
+
parent: {
|
|
826
|
+
page_id: pageId,
|
|
827
|
+
},
|
|
828
|
+
rich_text: [
|
|
829
|
+
{
|
|
830
|
+
text: {
|
|
831
|
+
content: 'This is a comment on the page.',
|
|
832
|
+
},
|
|
833
|
+
},
|
|
834
|
+
],
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
return response;
|
|
838
|
+
}
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
### Create a Discussion Comment (Reply)
|
|
842
|
+
|
|
843
|
+
```javascript
|
|
844
|
+
async function createDiscussionComment(discussionId) {
|
|
845
|
+
const response = await notion.comments.create({
|
|
846
|
+
discussion_id: discussionId,
|
|
847
|
+
rich_text: [
|
|
848
|
+
{
|
|
849
|
+
text: {
|
|
850
|
+
content: 'This is a reply to an existing comment.',
|
|
851
|
+
},
|
|
852
|
+
},
|
|
853
|
+
],
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
return response;
|
|
857
|
+
}
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
### List Comments
|
|
861
|
+
|
|
862
|
+
```javascript
|
|
863
|
+
async function listComments(blockId) {
|
|
864
|
+
const response = await notion.comments.list({
|
|
865
|
+
block_id: blockId,
|
|
866
|
+
});
|
|
867
|
+
|
|
868
|
+
console.log('Comments:', response.results);
|
|
869
|
+
return response.results;
|
|
870
|
+
}
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
## Pagination
|
|
874
|
+
|
|
875
|
+
### Manual Pagination
|
|
876
|
+
|
|
877
|
+
```javascript
|
|
878
|
+
async function getAllPages(databaseId) {
|
|
879
|
+
let hasMore = true;
|
|
880
|
+
let startCursor = undefined;
|
|
881
|
+
let allResults = [];
|
|
882
|
+
|
|
883
|
+
while (hasMore) {
|
|
884
|
+
const response = await notion.databases.query({
|
|
885
|
+
database_id: databaseId,
|
|
886
|
+
start_cursor: startCursor,
|
|
887
|
+
page_size: 100,
|
|
888
|
+
});
|
|
889
|
+
|
|
890
|
+
allResults = allResults.concat(response.results);
|
|
891
|
+
hasMore = response.has_more;
|
|
892
|
+
startCursor = response.next_cursor;
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
console.log(`Retrieved ${allResults.length} total results`);
|
|
896
|
+
return allResults;
|
|
897
|
+
}
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
### Using Pagination Helpers
|
|
901
|
+
|
|
902
|
+
```javascript
|
|
903
|
+
const { iteratePaginatedAPI, collectPaginatedAPI } = require('@notionhq/client');
|
|
904
|
+
|
|
905
|
+
// Iterate through paginated results
|
|
906
|
+
async function iterateBlocks(blockId) {
|
|
907
|
+
for await (const block of iteratePaginatedAPI(notion.blocks.children.list, {
|
|
908
|
+
block_id: blockId,
|
|
909
|
+
})) {
|
|
910
|
+
console.log('Block type:', block.type);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
// Collect all paginated results at once
|
|
915
|
+
async function collectAllBlocks(blockId) {
|
|
916
|
+
const blocks = await collectPaginatedAPI(notion.blocks.children.list, {
|
|
917
|
+
block_id: blockId,
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
console.log(`Total blocks: ${blocks.length}`);
|
|
921
|
+
return blocks;
|
|
922
|
+
}
|
|
923
|
+
```
|
|
924
|
+
|
|
925
|
+
## Error Handling
|
|
926
|
+
|
|
927
|
+
### Basic Error Handling
|
|
928
|
+
|
|
929
|
+
```javascript
|
|
930
|
+
const { Client, APIErrorCode } = require('@notionhq/client');
|
|
931
|
+
|
|
932
|
+
const notion = new Client({ auth: process.env.NOTION_TOKEN });
|
|
933
|
+
|
|
934
|
+
async function handleErrors() {
|
|
935
|
+
try {
|
|
936
|
+
const response = await notion.pages.retrieve({
|
|
937
|
+
page_id: 'invalid-id',
|
|
938
|
+
});
|
|
939
|
+
} catch (error) {
|
|
940
|
+
if (error.code === APIErrorCode.ObjectNotFound) {
|
|
941
|
+
console.error('Page not found');
|
|
942
|
+
} else if (error.code === APIErrorCode.Unauthorized) {
|
|
943
|
+
console.error('Invalid API token');
|
|
944
|
+
} else if (error.code === APIErrorCode.RestrictedResource) {
|
|
945
|
+
console.error('Access denied - integration not shared with this resource');
|
|
946
|
+
} else if (error.code === APIErrorCode.RateLimited) {
|
|
947
|
+
console.error('Rate limit exceeded');
|
|
948
|
+
} else {
|
|
949
|
+
console.error('Error:', error.message);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
### TypeScript Error Handling
|
|
956
|
+
|
|
957
|
+
```typescript
|
|
958
|
+
import { Client, isNotionClientError, ClientErrorCode, APIErrorCode } from '@notionhq/client';
|
|
959
|
+
|
|
960
|
+
const notion = new Client({ auth: process.env.NOTION_TOKEN });
|
|
961
|
+
|
|
962
|
+
async function handleErrorsTypescript() {
|
|
963
|
+
try {
|
|
964
|
+
const response = await notion.pages.retrieve({
|
|
965
|
+
page_id: 'some-id',
|
|
966
|
+
});
|
|
967
|
+
} catch (error: unknown) {
|
|
968
|
+
if (isNotionClientError(error)) {
|
|
969
|
+
switch (error.code) {
|
|
970
|
+
case ClientErrorCode.RequestTimeout:
|
|
971
|
+
console.error('Request timed out');
|
|
972
|
+
break;
|
|
973
|
+
case APIErrorCode.ObjectNotFound:
|
|
974
|
+
console.error('Object not found');
|
|
975
|
+
break;
|
|
976
|
+
case APIErrorCode.Unauthorized:
|
|
977
|
+
console.error('Unauthorized');
|
|
978
|
+
break;
|
|
979
|
+
case APIErrorCode.RestrictedResource:
|
|
980
|
+
console.error('Access denied');
|
|
981
|
+
break;
|
|
982
|
+
case APIErrorCode.RateLimited:
|
|
983
|
+
console.error('Rate limited');
|
|
984
|
+
break;
|
|
985
|
+
default:
|
|
986
|
+
console.error('Unknown error:', error);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
### Common Error Codes
|
|
994
|
+
|
|
995
|
+
| Error Code | Description |
|
|
996
|
+
|------------|-------------|
|
|
997
|
+
| `ObjectNotFound` | The requested resource doesn't exist |
|
|
998
|
+
| `Unauthorized` | Invalid or missing API token |
|
|
999
|
+
| `RestrictedResource` | Integration doesn't have access to the resource |
|
|
1000
|
+
| `RateLimited` | Too many requests, retry after delay |
|
|
1001
|
+
| `ValidationError` | Invalid request parameters |
|
|
1002
|
+
| `ConflictError` | Resource conflict (e.g., duplicate) |
|
|
1003
|
+
| `RequestTimeout` | Request took too long |
|
|
1004
|
+
|
|
1005
|
+
## Advanced Features
|
|
1006
|
+
|
|
1007
|
+
### Custom Request
|
|
1008
|
+
|
|
1009
|
+
```javascript
|
|
1010
|
+
async function customRequest() {
|
|
1011
|
+
const response = await notion.request({
|
|
1012
|
+
path: 'comments',
|
|
1013
|
+
method: 'post',
|
|
1014
|
+
body: {
|
|
1015
|
+
parent: { page_id: '5c6a28216bb14a7eb6e1c50111515c3d' },
|
|
1016
|
+
rich_text: [{ text: { content: 'Custom request comment' } }],
|
|
1017
|
+
},
|
|
1018
|
+
});
|
|
1019
|
+
|
|
1020
|
+
return response;
|
|
1021
|
+
}
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
### TypeScript Type Guards
|
|
1025
|
+
|
|
1026
|
+
```typescript
|
|
1027
|
+
import { isFullPageOrDataSource, isFullBlock } from '@notionhq/client';
|
|
1028
|
+
|
|
1029
|
+
async function useTypeGuards(dataSourceId: string) {
|
|
1030
|
+
const response = await notion.dataSources.query({
|
|
1031
|
+
data_source_id: dataSourceId,
|
|
1032
|
+
});
|
|
1033
|
+
|
|
1034
|
+
for (const page of response.results) {
|
|
1035
|
+
if (isFullPageOrDataSource(page)) {
|
|
1036
|
+
// Now TypeScript knows page has full properties
|
|
1037
|
+
console.log('Created at:', page.created_time);
|
|
1038
|
+
console.log('Last edited:', page.last_edited_time);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
async function checkBlockType(blockId: string) {
|
|
1044
|
+
const block = await notion.blocks.retrieve({ block_id: blockId });
|
|
1045
|
+
|
|
1046
|
+
if (isFullBlock(block)) {
|
|
1047
|
+
console.log('Block type:', block.type);
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
```
|
|
1051
|
+
|
|
1052
|
+
### Rich Text Formatting
|
|
1053
|
+
|
|
1054
|
+
```javascript
|
|
1055
|
+
const richText = [
|
|
1056
|
+
{
|
|
1057
|
+
type: 'text',
|
|
1058
|
+
text: { content: 'Plain text ' },
|
|
1059
|
+
},
|
|
1060
|
+
{
|
|
1061
|
+
type: 'text',
|
|
1062
|
+
text: { content: 'bold text' },
|
|
1063
|
+
annotations: { bold: true },
|
|
1064
|
+
},
|
|
1065
|
+
{
|
|
1066
|
+
type: 'text',
|
|
1067
|
+
text: { content: ' ' },
|
|
1068
|
+
},
|
|
1069
|
+
{
|
|
1070
|
+
type: 'text',
|
|
1071
|
+
text: { content: 'italic text' },
|
|
1072
|
+
annotations: { italic: true },
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
type: 'text',
|
|
1076
|
+
text: { content: ' ' },
|
|
1077
|
+
},
|
|
1078
|
+
{
|
|
1079
|
+
type: 'text',
|
|
1080
|
+
text: { content: 'strikethrough' },
|
|
1081
|
+
annotations: { strikethrough: true },
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
type: 'text',
|
|
1085
|
+
text: { content: ' ' },
|
|
1086
|
+
},
|
|
1087
|
+
{
|
|
1088
|
+
type: 'text',
|
|
1089
|
+
text: { content: 'underline' },
|
|
1090
|
+
annotations: { underline: true },
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
type: 'text',
|
|
1094
|
+
text: { content: ' ' },
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
type: 'text',
|
|
1098
|
+
text: { content: 'code' },
|
|
1099
|
+
annotations: { code: true },
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
type: 'text',
|
|
1103
|
+
text: { content: ' ' },
|
|
1104
|
+
},
|
|
1105
|
+
{
|
|
1106
|
+
type: 'text',
|
|
1107
|
+
text: { content: 'colored text' },
|
|
1108
|
+
annotations: { color: 'red' },
|
|
1109
|
+
},
|
|
1110
|
+
{
|
|
1111
|
+
type: 'text',
|
|
1112
|
+
text: { content: ' ' },
|
|
1113
|
+
},
|
|
1114
|
+
{
|
|
1115
|
+
type: 'text',
|
|
1116
|
+
text: { content: 'link text', link: { url: 'https://notion.so' } },
|
|
1117
|
+
},
|
|
1118
|
+
];
|
|
1119
|
+
```
|
|
1120
|
+
|
|
1121
|
+
### Property Types
|
|
1122
|
+
|
|
1123
|
+
```javascript
|
|
1124
|
+
// Title property
|
|
1125
|
+
const titleProperty = {
|
|
1126
|
+
title: [
|
|
1127
|
+
{
|
|
1128
|
+
text: { content: 'Page Title' },
|
|
1129
|
+
},
|
|
1130
|
+
],
|
|
1131
|
+
};
|
|
1132
|
+
|
|
1133
|
+
// Rich text property
|
|
1134
|
+
const richTextProperty = {
|
|
1135
|
+
rich_text: [
|
|
1136
|
+
{
|
|
1137
|
+
text: { content: 'Some text content' },
|
|
1138
|
+
},
|
|
1139
|
+
],
|
|
1140
|
+
};
|
|
1141
|
+
|
|
1142
|
+
// Number property
|
|
1143
|
+
const numberProperty = {
|
|
1144
|
+
number: 42,
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
// Select property
|
|
1148
|
+
const selectProperty = {
|
|
1149
|
+
select: {
|
|
1150
|
+
name: 'Option 1',
|
|
1151
|
+
},
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
// Multi-select property
|
|
1155
|
+
const multiSelectProperty = {
|
|
1156
|
+
multi_select: [
|
|
1157
|
+
{ name: 'Tag 1' },
|
|
1158
|
+
{ name: 'Tag 2' },
|
|
1159
|
+
],
|
|
1160
|
+
};
|
|
1161
|
+
|
|
1162
|
+
// Date property
|
|
1163
|
+
const dateProperty = {
|
|
1164
|
+
date: {
|
|
1165
|
+
start: '2025-01-01',
|
|
1166
|
+
end: '2025-01-31',
|
|
1167
|
+
},
|
|
1168
|
+
};
|
|
1169
|
+
|
|
1170
|
+
// Checkbox property
|
|
1171
|
+
const checkboxProperty = {
|
|
1172
|
+
checkbox: true,
|
|
1173
|
+
};
|
|
1174
|
+
|
|
1175
|
+
// URL property
|
|
1176
|
+
const urlProperty = {
|
|
1177
|
+
url: 'https://notion.so',
|
|
1178
|
+
};
|
|
1179
|
+
|
|
1180
|
+
// Email property
|
|
1181
|
+
const emailProperty = {
|
|
1182
|
+
email: 'user@example.com',
|
|
1183
|
+
};
|
|
1184
|
+
|
|
1185
|
+
// Phone number property
|
|
1186
|
+
const phoneProperty = {
|
|
1187
|
+
phone_number: '+1-555-0100',
|
|
1188
|
+
};
|
|
1189
|
+
|
|
1190
|
+
// Status property
|
|
1191
|
+
const statusProperty = {
|
|
1192
|
+
status: {
|
|
1193
|
+
name: 'In Progress',
|
|
1194
|
+
},
|
|
1195
|
+
};
|
|
1196
|
+
|
|
1197
|
+
// People property
|
|
1198
|
+
const peopleProperty = {
|
|
1199
|
+
people: [
|
|
1200
|
+
{
|
|
1201
|
+
object: 'user',
|
|
1202
|
+
id: 'user-id-here',
|
|
1203
|
+
},
|
|
1204
|
+
],
|
|
1205
|
+
};
|
|
1206
|
+
|
|
1207
|
+
// Files property
|
|
1208
|
+
const filesProperty = {
|
|
1209
|
+
files: [
|
|
1210
|
+
{
|
|
1211
|
+
name: 'Document.pdf',
|
|
1212
|
+
type: 'external',
|
|
1213
|
+
external: {
|
|
1214
|
+
url: 'https://example.com/document.pdf',
|
|
1215
|
+
},
|
|
1216
|
+
},
|
|
1217
|
+
],
|
|
1218
|
+
};
|
|
1219
|
+
|
|
1220
|
+
// Relation property
|
|
1221
|
+
const relationProperty = {
|
|
1222
|
+
relation: [
|
|
1223
|
+
{
|
|
1224
|
+
id: 'related-page-id',
|
|
1225
|
+
},
|
|
1226
|
+
],
|
|
1227
|
+
};
|
|
1228
|
+
```
|
|
1229
|
+
|
|
1230
|
+
## Complete Example: Task Management System
|
|
1231
|
+
|
|
1232
|
+
```javascript
|
|
1233
|
+
const { Client } = require('@notionhq/client');
|
|
1234
|
+
|
|
1235
|
+
const notion = new Client({
|
|
1236
|
+
auth: process.env.NOTION_TOKEN,
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
async function createTaskManagementSystem() {
|
|
1240
|
+
// 1. Create a database for tasks
|
|
1241
|
+
const database = await notion.databases.create({
|
|
1242
|
+
parent: {
|
|
1243
|
+
type: 'page_id',
|
|
1244
|
+
page_id: process.env.PARENT_PAGE_ID,
|
|
1245
|
+
},
|
|
1246
|
+
title: [
|
|
1247
|
+
{
|
|
1248
|
+
type: 'text',
|
|
1249
|
+
text: { content: 'Task Manager' },
|
|
1250
|
+
},
|
|
1251
|
+
],
|
|
1252
|
+
properties: {
|
|
1253
|
+
Name: {
|
|
1254
|
+
title: {},
|
|
1255
|
+
},
|
|
1256
|
+
Status: {
|
|
1257
|
+
status: {
|
|
1258
|
+
options: [
|
|
1259
|
+
{ name: 'Not started', color: 'red' },
|
|
1260
|
+
{ name: 'In progress', color: 'yellow' },
|
|
1261
|
+
{ name: 'Completed', color: 'green' },
|
|
1262
|
+
],
|
|
1263
|
+
},
|
|
1264
|
+
},
|
|
1265
|
+
Priority: {
|
|
1266
|
+
select: {
|
|
1267
|
+
options: [
|
|
1268
|
+
{ name: 'High', color: 'red' },
|
|
1269
|
+
{ name: 'Medium', color: 'yellow' },
|
|
1270
|
+
{ name: 'Low', color: 'gray' },
|
|
1271
|
+
],
|
|
1272
|
+
},
|
|
1273
|
+
},
|
|
1274
|
+
'Due Date': {
|
|
1275
|
+
date: {},
|
|
1276
|
+
},
|
|
1277
|
+
Tags: {
|
|
1278
|
+
multi_select: {
|
|
1279
|
+
options: [
|
|
1280
|
+
{ name: 'Bug', color: 'red' },
|
|
1281
|
+
{ name: 'Feature', color: 'blue' },
|
|
1282
|
+
{ name: 'Documentation', color: 'purple' },
|
|
1283
|
+
],
|
|
1284
|
+
},
|
|
1285
|
+
},
|
|
1286
|
+
Assignee: {
|
|
1287
|
+
people: {},
|
|
1288
|
+
},
|
|
1289
|
+
},
|
|
1290
|
+
});
|
|
1291
|
+
|
|
1292
|
+
console.log('Database created:', database.id);
|
|
1293
|
+
|
|
1294
|
+
// 2. Create a task
|
|
1295
|
+
const task = await notion.pages.create({
|
|
1296
|
+
parent: {
|
|
1297
|
+
database_id: database.id,
|
|
1298
|
+
},
|
|
1299
|
+
properties: {
|
|
1300
|
+
Name: {
|
|
1301
|
+
title: [
|
|
1302
|
+
{
|
|
1303
|
+
text: { content: 'Implement user authentication' },
|
|
1304
|
+
},
|
|
1305
|
+
],
|
|
1306
|
+
},
|
|
1307
|
+
Status: {
|
|
1308
|
+
status: { name: 'In progress' },
|
|
1309
|
+
},
|
|
1310
|
+
Priority: {
|
|
1311
|
+
select: { name: 'High' },
|
|
1312
|
+
},
|
|
1313
|
+
'Due Date': {
|
|
1314
|
+
date: { start: '2025-02-01' },
|
|
1315
|
+
},
|
|
1316
|
+
Tags: {
|
|
1317
|
+
multi_select: [{ name: 'Feature' }],
|
|
1318
|
+
},
|
|
1319
|
+
},
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
console.log('Task created:', task.id);
|
|
1323
|
+
|
|
1324
|
+
// 3. Add content to the task
|
|
1325
|
+
await notion.blocks.children.append({
|
|
1326
|
+
block_id: task.id,
|
|
1327
|
+
children: [
|
|
1328
|
+
{
|
|
1329
|
+
object: 'block',
|
|
1330
|
+
type: 'heading_2',
|
|
1331
|
+
heading_2: {
|
|
1332
|
+
rich_text: [{ text: { content: 'Task Details' } }],
|
|
1333
|
+
},
|
|
1334
|
+
},
|
|
1335
|
+
{
|
|
1336
|
+
object: 'block',
|
|
1337
|
+
type: 'paragraph',
|
|
1338
|
+
paragraph: {
|
|
1339
|
+
rich_text: [
|
|
1340
|
+
{
|
|
1341
|
+
text: {
|
|
1342
|
+
content: 'Implement OAuth 2.0 authentication for user login.',
|
|
1343
|
+
},
|
|
1344
|
+
},
|
|
1345
|
+
],
|
|
1346
|
+
},
|
|
1347
|
+
},
|
|
1348
|
+
{
|
|
1349
|
+
object: 'block',
|
|
1350
|
+
type: 'heading_3',
|
|
1351
|
+
heading_3: {
|
|
1352
|
+
rich_text: [{ text: { content: 'Requirements' } }],
|
|
1353
|
+
},
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
object: 'block',
|
|
1357
|
+
type: 'to_do',
|
|
1358
|
+
to_do: {
|
|
1359
|
+
rich_text: [{ text: { content: 'Set up OAuth provider' } }],
|
|
1360
|
+
checked: false,
|
|
1361
|
+
},
|
|
1362
|
+
},
|
|
1363
|
+
{
|
|
1364
|
+
object: 'block',
|
|
1365
|
+
type: 'to_do',
|
|
1366
|
+
to_do: {
|
|
1367
|
+
rich_text: [{ text: { content: 'Create login page' } }],
|
|
1368
|
+
checked: false,
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
{
|
|
1372
|
+
object: 'block',
|
|
1373
|
+
type: 'to_do',
|
|
1374
|
+
to_do: {
|
|
1375
|
+
rich_text: [{ text: { content: 'Test authentication flow' } }],
|
|
1376
|
+
checked: false,
|
|
1377
|
+
},
|
|
1378
|
+
},
|
|
1379
|
+
],
|
|
1380
|
+
});
|
|
1381
|
+
|
|
1382
|
+
// 4. Add a comment
|
|
1383
|
+
await notion.comments.create({
|
|
1384
|
+
parent: { page_id: task.id },
|
|
1385
|
+
rich_text: [
|
|
1386
|
+
{
|
|
1387
|
+
text: { content: 'Starting work on this task today.' },
|
|
1388
|
+
},
|
|
1389
|
+
],
|
|
1390
|
+
});
|
|
1391
|
+
|
|
1392
|
+
// 5. Query all high priority tasks
|
|
1393
|
+
const highPriorityTasks = await notion.databases.query({
|
|
1394
|
+
database_id: database.id,
|
|
1395
|
+
filter: {
|
|
1396
|
+
property: 'Priority',
|
|
1397
|
+
select: {
|
|
1398
|
+
equals: 'High',
|
|
1399
|
+
},
|
|
1400
|
+
},
|
|
1401
|
+
sorts: [
|
|
1402
|
+
{
|
|
1403
|
+
property: 'Due Date',
|
|
1404
|
+
direction: 'ascending',
|
|
1405
|
+
},
|
|
1406
|
+
],
|
|
1407
|
+
});
|
|
1408
|
+
|
|
1409
|
+
console.log('High priority tasks:', highPriorityTasks.results.length);
|
|
1410
|
+
|
|
1411
|
+
// 6. Update task status
|
|
1412
|
+
await notion.pages.update({
|
|
1413
|
+
page_id: task.id,
|
|
1414
|
+
properties: {
|
|
1415
|
+
Status: {
|
|
1416
|
+
status: { name: 'Completed' },
|
|
1417
|
+
},
|
|
1418
|
+
},
|
|
1419
|
+
});
|
|
1420
|
+
|
|
1421
|
+
console.log('Task marked as completed');
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
// Run the example
|
|
1425
|
+
createTaskManagementSystem().catch(console.error);
|
|
1426
|
+
```
|
|
1427
|
+
|
|
1428
|
+
## Useful Links
|
|
1429
|
+
|
|
1430
|
+
- Documentation: https://developers.notion.com/
|
|
1431
|
+
- API Reference: https://developers.notion.com/reference/
|
|
1432
|
+
- SDK Repository: https://github.com/makenotion/notion-sdk-js
|
|
1433
|
+
- NPM Package: https://www.npmjs.com/package/@notionhq/client
|
|
1434
|
+
- Create Integration: https://www.notion.com/my-integrations
|
|
1435
|
+
- Community: Notion Developers Slack
|