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,1400 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: workspace-api
|
|
3
|
+
description: "Notion Python SDK for interacting with Notion workspaces, pages, and databases via the official API."
|
|
4
|
+
metadata:
|
|
5
|
+
languages: "python"
|
|
6
|
+
versions: "2.6.0"
|
|
7
|
+
updated-on: "2026-03-01"
|
|
8
|
+
source: maintainer
|
|
9
|
+
tags: "notion,api,workspace,pages,databases"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Notion API Python 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
|
+
https://ramnes.github.io/notion-sdk-py/
|
|
19
|
+
|
|
20
|
+
## Golden Rule: Use the Correct and Current SDK
|
|
21
|
+
|
|
22
|
+
Always use the Notion Python SDK to interact with Notion workspaces, which is the standard library for all Notion API interactions. Do not use legacy libraries or unofficial SDKs.
|
|
23
|
+
|
|
24
|
+
- **Library Name:** Notion Python SDK
|
|
25
|
+
- **PyPI Package:** `notion-client`
|
|
26
|
+
- **Legacy Libraries**: `notion-py`, `notion`, `notion-sdk`, and other unofficial packages are not recommended
|
|
27
|
+
|
|
28
|
+
**Installation:**
|
|
29
|
+
|
|
30
|
+
- **Correct:** `pip install notion-client`
|
|
31
|
+
|
|
32
|
+
**APIs and Usage:**
|
|
33
|
+
|
|
34
|
+
- **Correct:** `from notion_client import Client`
|
|
35
|
+
- **Correct:** `notion = Client(auth=os.environ["NOTION_TOKEN"])`
|
|
36
|
+
- **Correct:** `notion.pages.create(...)`
|
|
37
|
+
- **Correct:** `notion.databases.query(...)`
|
|
38
|
+
- **Correct:** `notion.data_sources.query(...)`
|
|
39
|
+
- **Incorrect:** `NotionClient` or `NotionAPI` from other packages
|
|
40
|
+
- **Incorrect:** Legacy notion-py APIs
|
|
41
|
+
|
|
42
|
+
## Installation
|
|
43
|
+
|
|
44
|
+
Install the Notion Python SDK using pip:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
pip install notion-client
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Set your environment variable for the Notion API token:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
export NOTION_TOKEN="your_integration_token_here"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
You can obtain an integration token by creating a new integration at:
|
|
57
|
+
https://www.notion.com/my-integrations
|
|
58
|
+
|
|
59
|
+
## Initialization and API Key
|
|
60
|
+
|
|
61
|
+
The `notion-client` library requires creating a `Client` instance for all API calls.
|
|
62
|
+
|
|
63
|
+
- Always use `notion = Client(auth=token)` to create an instance.
|
|
64
|
+
- Set the `NOTION_TOKEN` environment variable for security.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import os
|
|
68
|
+
from notion_client import Client
|
|
69
|
+
|
|
70
|
+
# Uses the NOTION_TOKEN environment variable
|
|
71
|
+
notion = Client(auth=os.environ["NOTION_TOKEN"])
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Client Configuration Options
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from notion_client import Client
|
|
78
|
+
|
|
79
|
+
notion = Client(
|
|
80
|
+
auth=os.environ["NOTION_TOKEN"],
|
|
81
|
+
log_level="DEBUG", # Logging verbosity: DEBUG, INFO, WARNING, ERROR
|
|
82
|
+
timeout_ms=60000, # Request timeout in milliseconds (default: 60000)
|
|
83
|
+
)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Async Client
|
|
87
|
+
|
|
88
|
+
The SDK supports async/await operations:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
import os
|
|
92
|
+
from notion_client import AsyncClient
|
|
93
|
+
|
|
94
|
+
async_notion = AsyncClient(auth=os.environ["NOTION_TOKEN"])
|
|
95
|
+
|
|
96
|
+
# Use with async/await
|
|
97
|
+
async def get_users():
|
|
98
|
+
response = await async_notion.users.list()
|
|
99
|
+
return response
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Important API Version Changes (2025-09-03)
|
|
103
|
+
|
|
104
|
+
As of API version 2025-09-03, Notion separated databases and data sources:
|
|
105
|
+
|
|
106
|
+
- **Databases** parent one or more data sources
|
|
107
|
+
- **Data Sources** each parent zero or more pages
|
|
108
|
+
- Use `notion.data_sources.query()` instead of `notion.databases.query()` for newer implementations
|
|
109
|
+
|
|
110
|
+
## Pages API
|
|
111
|
+
|
|
112
|
+
### Create a Page
|
|
113
|
+
|
|
114
|
+
Create a new page as a child of an existing page:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from notion_client import Client
|
|
118
|
+
import os
|
|
119
|
+
|
|
120
|
+
notion = Client(auth=os.environ["NOTION_TOKEN"])
|
|
121
|
+
|
|
122
|
+
def create_page():
|
|
123
|
+
response = notion.pages.create(
|
|
124
|
+
parent={
|
|
125
|
+
"page_id": "494c87d072c44cf6960f55f8427f7692"
|
|
126
|
+
},
|
|
127
|
+
properties={
|
|
128
|
+
"title": {
|
|
129
|
+
"type": "title",
|
|
130
|
+
"title": [
|
|
131
|
+
{
|
|
132
|
+
"type": "text",
|
|
133
|
+
"text": {"content": "A note from your pals at Notion"}
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
return response
|
|
141
|
+
|
|
142
|
+
page = create_page()
|
|
143
|
+
print(page)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Create a Page in a Data Source (Database)
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
def create_page_in_data_source():
|
|
150
|
+
response = notion.pages.create(
|
|
151
|
+
parent={
|
|
152
|
+
"data_source_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af"
|
|
153
|
+
},
|
|
154
|
+
properties={
|
|
155
|
+
"Name": {
|
|
156
|
+
"title": [
|
|
157
|
+
{
|
|
158
|
+
"text": {
|
|
159
|
+
"content": "Golden Gate Bridge"
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
]
|
|
163
|
+
},
|
|
164
|
+
"Tags": {
|
|
165
|
+
"multi_select": [
|
|
166
|
+
{"name": "Landmark"},
|
|
167
|
+
{"name": "San Francisco"}
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
"Status": {
|
|
171
|
+
"status": {
|
|
172
|
+
"name": "Active"
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
return response
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Create a Page with Content Blocks
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
def create_page_with_content():
|
|
185
|
+
response = notion.pages.create(
|
|
186
|
+
parent={
|
|
187
|
+
"page_id": "494c87d072c44cf6960f55f8427f7692"
|
|
188
|
+
},
|
|
189
|
+
properties={
|
|
190
|
+
"title": {
|
|
191
|
+
"title": [{"text": {"content": "My New Page"}}]
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
children=[
|
|
195
|
+
{
|
|
196
|
+
"object": "block",
|
|
197
|
+
"type": "heading_2",
|
|
198
|
+
"heading_2": {
|
|
199
|
+
"rich_text": [{"type": "text", "text": {"content": "Introduction"}}]
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"object": "block",
|
|
204
|
+
"type": "paragraph",
|
|
205
|
+
"paragraph": {
|
|
206
|
+
"rich_text": [
|
|
207
|
+
{
|
|
208
|
+
"type": "text",
|
|
209
|
+
"text": {"content": "This is a paragraph with "}
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
"type": "text",
|
|
213
|
+
"text": {"content": "bold text"},
|
|
214
|
+
"annotations": {"bold": True}
|
|
215
|
+
}
|
|
216
|
+
]
|
|
217
|
+
}
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
"object": "block",
|
|
221
|
+
"type": "bulleted_list_item",
|
|
222
|
+
"bulleted_list_item": {
|
|
223
|
+
"rich_text": [{"type": "text", "text": {"content": "First bullet point"}}]
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
return response
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Retrieve a Page
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
def retrieve_page(page_id):
|
|
236
|
+
response = notion.pages.retrieve(page_id=page_id)
|
|
237
|
+
|
|
238
|
+
print("Page title:", response["properties"]["title"])
|
|
239
|
+
print("Created at:", response["created_time"])
|
|
240
|
+
print("Last edited:", response["last_edited_time"])
|
|
241
|
+
|
|
242
|
+
return response
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### Update Page Properties
|
|
246
|
+
|
|
247
|
+
```python
|
|
248
|
+
def update_page(page_id):
|
|
249
|
+
response = notion.pages.update(
|
|
250
|
+
page_id=page_id,
|
|
251
|
+
properties={
|
|
252
|
+
"Status": {
|
|
253
|
+
"status": {
|
|
254
|
+
"name": "Completed"
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
"Tags": {
|
|
258
|
+
"multi_select": [
|
|
259
|
+
{"name": "Updated"},
|
|
260
|
+
{"name": "Important"}
|
|
261
|
+
]
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
return response
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Archive (Trash) a Page
|
|
270
|
+
|
|
271
|
+
```python
|
|
272
|
+
def archive_page(page_id):
|
|
273
|
+
response = notion.pages.update(
|
|
274
|
+
page_id=page_id,
|
|
275
|
+
archived=True
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
return response
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Databases API
|
|
282
|
+
|
|
283
|
+
### Query a Database
|
|
284
|
+
|
|
285
|
+
```python
|
|
286
|
+
def query_database(database_id):
|
|
287
|
+
response = notion.databases.query(database_id=database_id)
|
|
288
|
+
|
|
289
|
+
print("Results:", response["results"])
|
|
290
|
+
return response
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Query with Filters and Sorting
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
def query_database_with_filters(database_id):
|
|
297
|
+
response = notion.databases.query(
|
|
298
|
+
database_id=database_id,
|
|
299
|
+
filter={
|
|
300
|
+
"and": [
|
|
301
|
+
{
|
|
302
|
+
"property": "Status",
|
|
303
|
+
"status": {
|
|
304
|
+
"equals": "Active"
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
"property": "Priority",
|
|
309
|
+
"select": {
|
|
310
|
+
"equals": "High"
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
]
|
|
314
|
+
},
|
|
315
|
+
sorts=[
|
|
316
|
+
{
|
|
317
|
+
"property": "Created",
|
|
318
|
+
"direction": "descending"
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
return response
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### Query Data Source (API Version 2025-09-03+)
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
def query_data_source(data_source_id):
|
|
330
|
+
response = notion.data_sources.query(
|
|
331
|
+
data_source_id=data_source_id,
|
|
332
|
+
filter={
|
|
333
|
+
"property": "Landmark",
|
|
334
|
+
"rich_text": {
|
|
335
|
+
"contains": "Bridge"
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
return response
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
### Filter Examples
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
# Text property contains value
|
|
347
|
+
text_filter = {
|
|
348
|
+
"property": "Description",
|
|
349
|
+
"rich_text": {"contains": "important"}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
# Checkbox equals value
|
|
353
|
+
checkbox_filter = {
|
|
354
|
+
"property": "Done",
|
|
355
|
+
"checkbox": {"equals": True}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
# Date is after specific date
|
|
359
|
+
date_filter = {
|
|
360
|
+
"property": "Due Date",
|
|
361
|
+
"date": {"after": "2025-01-01"}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
# Number greater than value
|
|
365
|
+
number_filter = {
|
|
366
|
+
"property": "Score",
|
|
367
|
+
"number": {"greater_than": 50}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
# Multi-select contains value
|
|
371
|
+
multi_select_filter = {
|
|
372
|
+
"property": "Tags",
|
|
373
|
+
"multi_select": {"contains": "urgent"}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
# Compound OR filter
|
|
377
|
+
or_filter = {
|
|
378
|
+
"or": [
|
|
379
|
+
{"property": "Tags", "multi_select": {"contains": "A"}},
|
|
380
|
+
{"property": "Tags", "multi_select": {"contains": "B"}}
|
|
381
|
+
]
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
# Compound AND filter
|
|
385
|
+
and_filter = {
|
|
386
|
+
"and": [
|
|
387
|
+
{"property": "Done", "checkbox": {"equals": False}},
|
|
388
|
+
{"property": "Priority", "select": {"equals": "High"}}
|
|
389
|
+
]
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Retrieve a Database
|
|
394
|
+
|
|
395
|
+
```python
|
|
396
|
+
def retrieve_database(database_id):
|
|
397
|
+
response = notion.databases.retrieve(database_id=database_id)
|
|
398
|
+
|
|
399
|
+
print("Database title:", response["title"])
|
|
400
|
+
print("Properties:", response["properties"])
|
|
401
|
+
|
|
402
|
+
return response
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### Create a Database
|
|
406
|
+
|
|
407
|
+
```python
|
|
408
|
+
def create_database(parent_page_id):
|
|
409
|
+
response = notion.databases.create(
|
|
410
|
+
parent={
|
|
411
|
+
"type": "page_id",
|
|
412
|
+
"page_id": parent_page_id
|
|
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
|
+
### Update Database Properties
|
|
462
|
+
|
|
463
|
+
```python
|
|
464
|
+
def update_database(database_id):
|
|
465
|
+
response = notion.databases.update(
|
|
466
|
+
database_id=database_id,
|
|
467
|
+
title=[
|
|
468
|
+
{
|
|
469
|
+
"text": {
|
|
470
|
+
"content": "Updated Task List"
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
],
|
|
474
|
+
properties={
|
|
475
|
+
"Status": {
|
|
476
|
+
"status": {
|
|
477
|
+
"options": [
|
|
478
|
+
{"name": "To Do", "color": "red"},
|
|
479
|
+
{"name": "Doing", "color": "yellow"},
|
|
480
|
+
{"name": "Done", "color": "green"}
|
|
481
|
+
]
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
return response
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
## Blocks API
|
|
491
|
+
|
|
492
|
+
### Retrieve Block Children
|
|
493
|
+
|
|
494
|
+
```python
|
|
495
|
+
def get_block_children(block_id):
|
|
496
|
+
response = notion.blocks.children.list(
|
|
497
|
+
block_id=block_id,
|
|
498
|
+
page_size=50
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
print("Number of blocks:", len(response["results"]))
|
|
502
|
+
return response["results"]
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### Append Block Children
|
|
506
|
+
|
|
507
|
+
```python
|
|
508
|
+
def append_block_children(block_id):
|
|
509
|
+
response = notion.blocks.children.append(
|
|
510
|
+
block_id=block_id,
|
|
511
|
+
children=[
|
|
512
|
+
{
|
|
513
|
+
"object": "block",
|
|
514
|
+
"type": "heading_2",
|
|
515
|
+
"heading_2": {
|
|
516
|
+
"rich_text": [
|
|
517
|
+
{
|
|
518
|
+
"type": "text",
|
|
519
|
+
"text": {"content": "New Section"}
|
|
520
|
+
}
|
|
521
|
+
]
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
"object": "block",
|
|
526
|
+
"type": "paragraph",
|
|
527
|
+
"paragraph": {
|
|
528
|
+
"rich_text": [
|
|
529
|
+
{
|
|
530
|
+
"type": "text",
|
|
531
|
+
"text": {"content": "This is a new paragraph."}
|
|
532
|
+
}
|
|
533
|
+
]
|
|
534
|
+
}
|
|
535
|
+
},
|
|
536
|
+
{
|
|
537
|
+
"object": "block",
|
|
538
|
+
"type": "to_do",
|
|
539
|
+
"to_do": {
|
|
540
|
+
"rich_text": [{"type": "text", "text": {"content": "Complete this task"}}],
|
|
541
|
+
"checked": False
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
]
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
return response
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
### Common Block Types
|
|
551
|
+
|
|
552
|
+
```python
|
|
553
|
+
# Heading blocks
|
|
554
|
+
heading_1 = {
|
|
555
|
+
"type": "heading_1",
|
|
556
|
+
"heading_1": {
|
|
557
|
+
"rich_text": [{"text": {"content": "Heading 1"}}]
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
heading_2 = {
|
|
562
|
+
"type": "heading_2",
|
|
563
|
+
"heading_2": {
|
|
564
|
+
"rich_text": [{"text": {"content": "Heading 2"}}]
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
heading_3 = {
|
|
569
|
+
"type": "heading_3",
|
|
570
|
+
"heading_3": {
|
|
571
|
+
"rich_text": [{"text": {"content": "Heading 3"}}]
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
# Paragraph with formatting
|
|
576
|
+
paragraph = {
|
|
577
|
+
"type": "paragraph",
|
|
578
|
+
"paragraph": {
|
|
579
|
+
"rich_text": [
|
|
580
|
+
{"text": {"content": "Normal text "}},
|
|
581
|
+
{"text": {"content": "bold"}, "annotations": {"bold": True}},
|
|
582
|
+
{"text": {"content": " and "}},
|
|
583
|
+
{"text": {"content": "italic"}, "annotations": {"italic": True}},
|
|
584
|
+
{"text": {"content": " and "}},
|
|
585
|
+
{"text": {"content": "code"}, "annotations": {"code": True}}
|
|
586
|
+
]
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
# Bulleted list item
|
|
591
|
+
bulleted_list_item = {
|
|
592
|
+
"type": "bulleted_list_item",
|
|
593
|
+
"bulleted_list_item": {
|
|
594
|
+
"rich_text": [{"text": {"content": "Bullet point"}}]
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
# Numbered list item
|
|
599
|
+
numbered_list_item = {
|
|
600
|
+
"type": "numbered_list_item",
|
|
601
|
+
"numbered_list_item": {
|
|
602
|
+
"rich_text": [{"text": {"content": "Numbered item"}}]
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
# To-do item
|
|
607
|
+
to_do = {
|
|
608
|
+
"type": "to_do",
|
|
609
|
+
"to_do": {
|
|
610
|
+
"rich_text": [{"text": {"content": "Task to complete"}}],
|
|
611
|
+
"checked": False
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
# Toggle block (collapsible)
|
|
616
|
+
toggle = {
|
|
617
|
+
"type": "toggle",
|
|
618
|
+
"toggle": {
|
|
619
|
+
"rich_text": [{"text": {"content": "Click to expand"}}]
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
# Quote
|
|
624
|
+
quote = {
|
|
625
|
+
"type": "quote",
|
|
626
|
+
"quote": {
|
|
627
|
+
"rich_text": [{"text": {"content": "This is a quote"}}]
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
# Callout
|
|
632
|
+
callout = {
|
|
633
|
+
"type": "callout",
|
|
634
|
+
"callout": {
|
|
635
|
+
"rich_text": [{"text": {"content": "Important note"}}],
|
|
636
|
+
"icon": {"emoji": "💡"}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
# Code block
|
|
641
|
+
code_block = {
|
|
642
|
+
"type": "code",
|
|
643
|
+
"code": {
|
|
644
|
+
"rich_text": [{"text": {"content": "x = 42"}}],
|
|
645
|
+
"language": "python"
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
# Divider
|
|
650
|
+
divider = {
|
|
651
|
+
"type": "divider",
|
|
652
|
+
"divider": {}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
# Image
|
|
656
|
+
image = {
|
|
657
|
+
"type": "image",
|
|
658
|
+
"image": {
|
|
659
|
+
"type": "external",
|
|
660
|
+
"external": {
|
|
661
|
+
"url": "https://example.com/image.png"
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
# Bookmark
|
|
667
|
+
bookmark = {
|
|
668
|
+
"type": "bookmark",
|
|
669
|
+
"bookmark": {
|
|
670
|
+
"url": "https://notion.so"
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
```
|
|
674
|
+
|
|
675
|
+
### Update a Block
|
|
676
|
+
|
|
677
|
+
```python
|
|
678
|
+
def update_block(block_id):
|
|
679
|
+
response = notion.blocks.update(
|
|
680
|
+
block_id=block_id,
|
|
681
|
+
paragraph={
|
|
682
|
+
"rich_text": [
|
|
683
|
+
{
|
|
684
|
+
"text": {
|
|
685
|
+
"content": "Updated paragraph content"
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
]
|
|
689
|
+
}
|
|
690
|
+
)
|
|
691
|
+
|
|
692
|
+
return response
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### Delete a Block
|
|
696
|
+
|
|
697
|
+
```python
|
|
698
|
+
def delete_block(block_id):
|
|
699
|
+
response = notion.blocks.delete(block_id=block_id)
|
|
700
|
+
return response
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
### Retrieve a Block
|
|
704
|
+
|
|
705
|
+
```python
|
|
706
|
+
def retrieve_block(block_id):
|
|
707
|
+
response = notion.blocks.retrieve(block_id=block_id)
|
|
708
|
+
|
|
709
|
+
print("Block type:", response["type"])
|
|
710
|
+
return response
|
|
711
|
+
```
|
|
712
|
+
|
|
713
|
+
## Users API
|
|
714
|
+
|
|
715
|
+
### List All Users
|
|
716
|
+
|
|
717
|
+
```python
|
|
718
|
+
def list_users():
|
|
719
|
+
response = notion.users.list()
|
|
720
|
+
|
|
721
|
+
print("Users:", response["results"])
|
|
722
|
+
return response["results"]
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
### Retrieve a User
|
|
726
|
+
|
|
727
|
+
```python
|
|
728
|
+
def retrieve_user(user_id):
|
|
729
|
+
response = notion.users.retrieve(user_id=user_id)
|
|
730
|
+
|
|
731
|
+
print("User name:", response["name"])
|
|
732
|
+
print("User type:", response["type"])
|
|
733
|
+
|
|
734
|
+
return response
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
### Retrieve Bot User (Your Integration)
|
|
738
|
+
|
|
739
|
+
```python
|
|
740
|
+
def retrieve_bot_user():
|
|
741
|
+
response = notion.users.me()
|
|
742
|
+
|
|
743
|
+
print("Bot name:", response["name"])
|
|
744
|
+
print("Bot ID:", response["id"])
|
|
745
|
+
|
|
746
|
+
return response
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
## Search API
|
|
750
|
+
|
|
751
|
+
### Basic Search
|
|
752
|
+
|
|
753
|
+
```python
|
|
754
|
+
def search_pages(query):
|
|
755
|
+
response = notion.search(
|
|
756
|
+
query=query,
|
|
757
|
+
filter={
|
|
758
|
+
"value": "page",
|
|
759
|
+
"property": "object"
|
|
760
|
+
},
|
|
761
|
+
sort={
|
|
762
|
+
"direction": "descending",
|
|
763
|
+
"timestamp": "last_edited_time"
|
|
764
|
+
}
|
|
765
|
+
)
|
|
766
|
+
|
|
767
|
+
return response["results"]
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
### Search for Databases
|
|
771
|
+
|
|
772
|
+
```python
|
|
773
|
+
def search_databases(query):
|
|
774
|
+
response = notion.search(
|
|
775
|
+
query=query,
|
|
776
|
+
filter={
|
|
777
|
+
"value": "database",
|
|
778
|
+
"property": "object"
|
|
779
|
+
}
|
|
780
|
+
)
|
|
781
|
+
|
|
782
|
+
return response["results"]
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Search All Content
|
|
786
|
+
|
|
787
|
+
```python
|
|
788
|
+
def search_all(query):
|
|
789
|
+
response = notion.search(
|
|
790
|
+
query=query,
|
|
791
|
+
page_size=100
|
|
792
|
+
)
|
|
793
|
+
|
|
794
|
+
print(f"Found {len(response['results'])} results")
|
|
795
|
+
return response["results"]
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
## Comments API
|
|
799
|
+
|
|
800
|
+
### Create a Comment
|
|
801
|
+
|
|
802
|
+
```python
|
|
803
|
+
def create_comment(page_id):
|
|
804
|
+
response = notion.comments.create(
|
|
805
|
+
parent={
|
|
806
|
+
"page_id": page_id
|
|
807
|
+
},
|
|
808
|
+
rich_text=[
|
|
809
|
+
{
|
|
810
|
+
"text": {
|
|
811
|
+
"content": "This is a comment on the page."
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
]
|
|
815
|
+
)
|
|
816
|
+
|
|
817
|
+
return response
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
### Create a Discussion Comment (Reply)
|
|
821
|
+
|
|
822
|
+
```python
|
|
823
|
+
def create_discussion_comment(discussion_id):
|
|
824
|
+
response = notion.comments.create(
|
|
825
|
+
discussion_id=discussion_id,
|
|
826
|
+
rich_text=[
|
|
827
|
+
{
|
|
828
|
+
"text": {
|
|
829
|
+
"content": "This is a reply to an existing comment."
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
]
|
|
833
|
+
)
|
|
834
|
+
|
|
835
|
+
return response
|
|
836
|
+
```
|
|
837
|
+
|
|
838
|
+
### List Comments
|
|
839
|
+
|
|
840
|
+
```python
|
|
841
|
+
def list_comments(block_id):
|
|
842
|
+
response = notion.comments.list(block_id=block_id)
|
|
843
|
+
|
|
844
|
+
print("Comments:", response["results"])
|
|
845
|
+
return response["results"]
|
|
846
|
+
```
|
|
847
|
+
|
|
848
|
+
## Pagination
|
|
849
|
+
|
|
850
|
+
### Manual Pagination
|
|
851
|
+
|
|
852
|
+
```python
|
|
853
|
+
def get_all_pages(database_id):
|
|
854
|
+
has_more = True
|
|
855
|
+
start_cursor = None
|
|
856
|
+
all_results = []
|
|
857
|
+
|
|
858
|
+
while has_more:
|
|
859
|
+
response = notion.databases.query(
|
|
860
|
+
database_id=database_id,
|
|
861
|
+
start_cursor=start_cursor,
|
|
862
|
+
page_size=100
|
|
863
|
+
)
|
|
864
|
+
|
|
865
|
+
all_results.extend(response["results"])
|
|
866
|
+
has_more = response["has_more"]
|
|
867
|
+
start_cursor = response.get("next_cursor")
|
|
868
|
+
|
|
869
|
+
print(f"Retrieved {len(all_results)} total results")
|
|
870
|
+
return all_results
|
|
871
|
+
```
|
|
872
|
+
|
|
873
|
+
### Using Pagination Helpers
|
|
874
|
+
|
|
875
|
+
```python
|
|
876
|
+
from notion_client import iterate_paginated_api, collect_paginated_api
|
|
877
|
+
|
|
878
|
+
# Iterate through paginated results
|
|
879
|
+
def iterate_blocks(block_id):
|
|
880
|
+
for block in iterate_paginated_api(
|
|
881
|
+
notion.blocks.children.list,
|
|
882
|
+
block_id=block_id
|
|
883
|
+
):
|
|
884
|
+
print("Block type:", block["type"])
|
|
885
|
+
|
|
886
|
+
# Collect all paginated results at once
|
|
887
|
+
def collect_all_blocks(block_id):
|
|
888
|
+
blocks = collect_paginated_api(
|
|
889
|
+
notion.blocks.children.list,
|
|
890
|
+
block_id=block_id
|
|
891
|
+
)
|
|
892
|
+
|
|
893
|
+
print(f"Total blocks: {len(blocks)}")
|
|
894
|
+
return blocks
|
|
895
|
+
```
|
|
896
|
+
|
|
897
|
+
### Async Pagination Helpers
|
|
898
|
+
|
|
899
|
+
```python
|
|
900
|
+
from notion_client import AsyncClient, async_iterate_paginated_api, async_collect_paginated_api
|
|
901
|
+
|
|
902
|
+
async_notion = AsyncClient(auth=os.environ["NOTION_TOKEN"])
|
|
903
|
+
|
|
904
|
+
# Async iteration
|
|
905
|
+
async def async_iterate_blocks(block_id):
|
|
906
|
+
async for block in async_iterate_paginated_api(
|
|
907
|
+
async_notion.blocks.children.list,
|
|
908
|
+
block_id=block_id
|
|
909
|
+
):
|
|
910
|
+
print("Block type:", block["type"])
|
|
911
|
+
|
|
912
|
+
# Async collection
|
|
913
|
+
async def async_collect_blocks(block_id):
|
|
914
|
+
blocks = await async_collect_paginated_api(
|
|
915
|
+
async_notion.blocks.children.list,
|
|
916
|
+
block_id=block_id
|
|
917
|
+
)
|
|
918
|
+
return blocks
|
|
919
|
+
```
|
|
920
|
+
|
|
921
|
+
## Error Handling
|
|
922
|
+
|
|
923
|
+
### Basic Error Handling
|
|
924
|
+
|
|
925
|
+
```python
|
|
926
|
+
from notion_client import Client, APIResponseError
|
|
927
|
+
|
|
928
|
+
notion = Client(auth=os.environ["NOTION_TOKEN"])
|
|
929
|
+
|
|
930
|
+
def handle_errors():
|
|
931
|
+
try:
|
|
932
|
+
response = notion.pages.retrieve(page_id="invalid-id")
|
|
933
|
+
except APIResponseError as error:
|
|
934
|
+
if error.code == "object_not_found":
|
|
935
|
+
print("Page not found")
|
|
936
|
+
elif error.code == "unauthorized":
|
|
937
|
+
print("Invalid API token")
|
|
938
|
+
elif error.code == "restricted_resource":
|
|
939
|
+
print("Access denied - integration not shared with this resource")
|
|
940
|
+
elif error.code == "rate_limited":
|
|
941
|
+
print("Rate limit exceeded")
|
|
942
|
+
else:
|
|
943
|
+
print(f"Error: {error.message}")
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
### Advanced Error Handling
|
|
947
|
+
|
|
948
|
+
```python
|
|
949
|
+
from notion_client import Client, APIResponseError, RequestTimeoutError
|
|
950
|
+
|
|
951
|
+
def advanced_error_handling():
|
|
952
|
+
try:
|
|
953
|
+
response = notion.pages.retrieve(page_id="some-id")
|
|
954
|
+
except RequestTimeoutError:
|
|
955
|
+
print("Request timed out")
|
|
956
|
+
except APIResponseError as error:
|
|
957
|
+
print(f"API Error: {error.code}")
|
|
958
|
+
print(f"Status: {error.status}")
|
|
959
|
+
print(f"Message: {error.message}")
|
|
960
|
+
|
|
961
|
+
# Access full response
|
|
962
|
+
if hasattr(error, 'response'):
|
|
963
|
+
print(f"Full response: {error.response}")
|
|
964
|
+
except Exception as error:
|
|
965
|
+
print(f"Unexpected error: {error}")
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
### Common Error Codes
|
|
969
|
+
|
|
970
|
+
| Error Code | Description |
|
|
971
|
+
|------------|-------------|
|
|
972
|
+
| `object_not_found` | The requested resource doesn't exist |
|
|
973
|
+
| `unauthorized` | Invalid or missing API token |
|
|
974
|
+
| `restricted_resource` | Integration doesn't have access to the resource |
|
|
975
|
+
| `rate_limited` | Too many requests, retry after delay |
|
|
976
|
+
| `validation_error` | Invalid request parameters |
|
|
977
|
+
| `conflict_error` | Resource conflict (e.g., duplicate) |
|
|
978
|
+
|
|
979
|
+
## Advanced Features
|
|
980
|
+
|
|
981
|
+
### Rich Text Formatting
|
|
982
|
+
|
|
983
|
+
```python
|
|
984
|
+
rich_text = [
|
|
985
|
+
{
|
|
986
|
+
"type": "text",
|
|
987
|
+
"text": {"content": "Plain text "}
|
|
988
|
+
},
|
|
989
|
+
{
|
|
990
|
+
"type": "text",
|
|
991
|
+
"text": {"content": "bold text"},
|
|
992
|
+
"annotations": {"bold": True}
|
|
993
|
+
},
|
|
994
|
+
{
|
|
995
|
+
"type": "text",
|
|
996
|
+
"text": {"content": " "}
|
|
997
|
+
},
|
|
998
|
+
{
|
|
999
|
+
"type": "text",
|
|
1000
|
+
"text": {"content": "italic text"},
|
|
1001
|
+
"annotations": {"italic": True}
|
|
1002
|
+
},
|
|
1003
|
+
{
|
|
1004
|
+
"type": "text",
|
|
1005
|
+
"text": {"content": " "}
|
|
1006
|
+
},
|
|
1007
|
+
{
|
|
1008
|
+
"type": "text",
|
|
1009
|
+
"text": {"content": "strikethrough"},
|
|
1010
|
+
"annotations": {"strikethrough": True}
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
"type": "text",
|
|
1014
|
+
"text": {"content": " "}
|
|
1015
|
+
},
|
|
1016
|
+
{
|
|
1017
|
+
"type": "text",
|
|
1018
|
+
"text": {"content": "underline"},
|
|
1019
|
+
"annotations": {"underline": True}
|
|
1020
|
+
},
|
|
1021
|
+
{
|
|
1022
|
+
"type": "text",
|
|
1023
|
+
"text": {"content": " "}
|
|
1024
|
+
},
|
|
1025
|
+
{
|
|
1026
|
+
"type": "text",
|
|
1027
|
+
"text": {"content": "code"},
|
|
1028
|
+
"annotations": {"code": True}
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
"type": "text",
|
|
1032
|
+
"text": {"content": " "}
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
"type": "text",
|
|
1036
|
+
"text": {"content": "colored text"},
|
|
1037
|
+
"annotations": {"color": "red"}
|
|
1038
|
+
},
|
|
1039
|
+
{
|
|
1040
|
+
"type": "text",
|
|
1041
|
+
"text": {"content": " "}
|
|
1042
|
+
},
|
|
1043
|
+
{
|
|
1044
|
+
"type": "text",
|
|
1045
|
+
"text": {"content": "link text", "link": {"url": "https://notion.so"}}
|
|
1046
|
+
}
|
|
1047
|
+
]
|
|
1048
|
+
```
|
|
1049
|
+
|
|
1050
|
+
### Property Types
|
|
1051
|
+
|
|
1052
|
+
```python
|
|
1053
|
+
# Title property
|
|
1054
|
+
title_property = {
|
|
1055
|
+
"title": [
|
|
1056
|
+
{
|
|
1057
|
+
"text": {"content": "Page Title"}
|
|
1058
|
+
}
|
|
1059
|
+
]
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
# Rich text property
|
|
1063
|
+
rich_text_property = {
|
|
1064
|
+
"rich_text": [
|
|
1065
|
+
{
|
|
1066
|
+
"text": {"content": "Some text content"}
|
|
1067
|
+
}
|
|
1068
|
+
]
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
# Number property
|
|
1072
|
+
number_property = {
|
|
1073
|
+
"number": 42
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
# Select property
|
|
1077
|
+
select_property = {
|
|
1078
|
+
"select": {
|
|
1079
|
+
"name": "Option 1"
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
# Multi-select property
|
|
1084
|
+
multi_select_property = {
|
|
1085
|
+
"multi_select": [
|
|
1086
|
+
{"name": "Tag 1"},
|
|
1087
|
+
{"name": "Tag 2"}
|
|
1088
|
+
]
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
# Date property
|
|
1092
|
+
date_property = {
|
|
1093
|
+
"date": {
|
|
1094
|
+
"start": "2025-01-01",
|
|
1095
|
+
"end": "2025-01-31"
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
# Checkbox property
|
|
1100
|
+
checkbox_property = {
|
|
1101
|
+
"checkbox": True
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
# URL property
|
|
1105
|
+
url_property = {
|
|
1106
|
+
"url": "https://notion.so"
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
# Email property
|
|
1110
|
+
email_property = {
|
|
1111
|
+
"email": "user@example.com"
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
# Phone number property
|
|
1115
|
+
phone_property = {
|
|
1116
|
+
"phone_number": "+1-555-0100"
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
# Status property
|
|
1120
|
+
status_property = {
|
|
1121
|
+
"status": {
|
|
1122
|
+
"name": "In Progress"
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
# People property
|
|
1127
|
+
people_property = {
|
|
1128
|
+
"people": [
|
|
1129
|
+
{
|
|
1130
|
+
"object": "user",
|
|
1131
|
+
"id": "user-id-here"
|
|
1132
|
+
}
|
|
1133
|
+
]
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
# Files property
|
|
1137
|
+
files_property = {
|
|
1138
|
+
"files": [
|
|
1139
|
+
{
|
|
1140
|
+
"name": "Document.pdf",
|
|
1141
|
+
"type": "external",
|
|
1142
|
+
"external": {
|
|
1143
|
+
"url": "https://example.com/document.pdf"
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
]
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
# Relation property
|
|
1150
|
+
relation_property = {
|
|
1151
|
+
"relation": [
|
|
1152
|
+
{
|
|
1153
|
+
"id": "related-page-id"
|
|
1154
|
+
}
|
|
1155
|
+
]
|
|
1156
|
+
}
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
## Complete Example: Task Management System
|
|
1160
|
+
|
|
1161
|
+
```python
|
|
1162
|
+
import os
|
|
1163
|
+
from notion_client import Client
|
|
1164
|
+
|
|
1165
|
+
notion = Client(auth=os.environ["NOTION_TOKEN"])
|
|
1166
|
+
|
|
1167
|
+
def create_task_management_system():
|
|
1168
|
+
# 1. Create a database for tasks
|
|
1169
|
+
database = notion.databases.create(
|
|
1170
|
+
parent={
|
|
1171
|
+
"type": "page_id",
|
|
1172
|
+
"page_id": os.environ["PARENT_PAGE_ID"]
|
|
1173
|
+
},
|
|
1174
|
+
title=[
|
|
1175
|
+
{
|
|
1176
|
+
"type": "text",
|
|
1177
|
+
"text": {"content": "Task Manager"}
|
|
1178
|
+
}
|
|
1179
|
+
],
|
|
1180
|
+
properties={
|
|
1181
|
+
"Name": {
|
|
1182
|
+
"title": {}
|
|
1183
|
+
},
|
|
1184
|
+
"Status": {
|
|
1185
|
+
"status": {
|
|
1186
|
+
"options": [
|
|
1187
|
+
{"name": "Not started", "color": "red"},
|
|
1188
|
+
{"name": "In progress", "color": "yellow"},
|
|
1189
|
+
{"name": "Completed", "color": "green"}
|
|
1190
|
+
]
|
|
1191
|
+
}
|
|
1192
|
+
},
|
|
1193
|
+
"Priority": {
|
|
1194
|
+
"select": {
|
|
1195
|
+
"options": [
|
|
1196
|
+
{"name": "High", "color": "red"},
|
|
1197
|
+
{"name": "Medium", "color": "yellow"},
|
|
1198
|
+
{"name": "Low", "color": "gray"}
|
|
1199
|
+
]
|
|
1200
|
+
}
|
|
1201
|
+
},
|
|
1202
|
+
"Due Date": {
|
|
1203
|
+
"date": {}
|
|
1204
|
+
},
|
|
1205
|
+
"Tags": {
|
|
1206
|
+
"multi_select": {
|
|
1207
|
+
"options": [
|
|
1208
|
+
{"name": "Bug", "color": "red"},
|
|
1209
|
+
{"name": "Feature", "color": "blue"},
|
|
1210
|
+
{"name": "Documentation", "color": "purple"}
|
|
1211
|
+
]
|
|
1212
|
+
}
|
|
1213
|
+
},
|
|
1214
|
+
"Assignee": {
|
|
1215
|
+
"people": {}
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
)
|
|
1219
|
+
|
|
1220
|
+
print(f"Database created: {database['id']}")
|
|
1221
|
+
|
|
1222
|
+
# 2. Create a task
|
|
1223
|
+
task = notion.pages.create(
|
|
1224
|
+
parent={
|
|
1225
|
+
"database_id": database["id"]
|
|
1226
|
+
},
|
|
1227
|
+
properties={
|
|
1228
|
+
"Name": {
|
|
1229
|
+
"title": [
|
|
1230
|
+
{
|
|
1231
|
+
"text": {"content": "Implement user authentication"}
|
|
1232
|
+
}
|
|
1233
|
+
]
|
|
1234
|
+
},
|
|
1235
|
+
"Status": {
|
|
1236
|
+
"status": {"name": "In progress"}
|
|
1237
|
+
},
|
|
1238
|
+
"Priority": {
|
|
1239
|
+
"select": {"name": "High"}
|
|
1240
|
+
},
|
|
1241
|
+
"Due Date": {
|
|
1242
|
+
"date": {"start": "2025-02-01"}
|
|
1243
|
+
},
|
|
1244
|
+
"Tags": {
|
|
1245
|
+
"multi_select": [{"name": "Feature"}]
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
)
|
|
1249
|
+
|
|
1250
|
+
print(f"Task created: {task['id']}")
|
|
1251
|
+
|
|
1252
|
+
# 3. Add content to the task
|
|
1253
|
+
notion.blocks.children.append(
|
|
1254
|
+
block_id=task["id"],
|
|
1255
|
+
children=[
|
|
1256
|
+
{
|
|
1257
|
+
"object": "block",
|
|
1258
|
+
"type": "heading_2",
|
|
1259
|
+
"heading_2": {
|
|
1260
|
+
"rich_text": [{"text": {"content": "Task Details"}}]
|
|
1261
|
+
}
|
|
1262
|
+
},
|
|
1263
|
+
{
|
|
1264
|
+
"object": "block",
|
|
1265
|
+
"type": "paragraph",
|
|
1266
|
+
"paragraph": {
|
|
1267
|
+
"rich_text": [
|
|
1268
|
+
{
|
|
1269
|
+
"text": {
|
|
1270
|
+
"content": "Implement OAuth 2.0 authentication for user login."
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
]
|
|
1274
|
+
}
|
|
1275
|
+
},
|
|
1276
|
+
{
|
|
1277
|
+
"object": "block",
|
|
1278
|
+
"type": "heading_3",
|
|
1279
|
+
"heading_3": {
|
|
1280
|
+
"rich_text": [{"text": {"content": "Requirements"}}]
|
|
1281
|
+
}
|
|
1282
|
+
},
|
|
1283
|
+
{
|
|
1284
|
+
"object": "block",
|
|
1285
|
+
"type": "to_do",
|
|
1286
|
+
"to_do": {
|
|
1287
|
+
"rich_text": [{"text": {"content": "Set up OAuth provider"}}],
|
|
1288
|
+
"checked": False
|
|
1289
|
+
}
|
|
1290
|
+
},
|
|
1291
|
+
{
|
|
1292
|
+
"object": "block",
|
|
1293
|
+
"type": "to_do",
|
|
1294
|
+
"to_do": {
|
|
1295
|
+
"rich_text": [{"text": {"content": "Create login page"}}],
|
|
1296
|
+
"checked": False
|
|
1297
|
+
}
|
|
1298
|
+
},
|
|
1299
|
+
{
|
|
1300
|
+
"object": "block",
|
|
1301
|
+
"type": "to_do",
|
|
1302
|
+
"to_do": {
|
|
1303
|
+
"rich_text": [{"text": {"content": "Test authentication flow"}}],
|
|
1304
|
+
"checked": False
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
]
|
|
1308
|
+
)
|
|
1309
|
+
|
|
1310
|
+
# 4. Add a comment
|
|
1311
|
+
notion.comments.create(
|
|
1312
|
+
parent={"page_id": task["id"]},
|
|
1313
|
+
rich_text=[
|
|
1314
|
+
{
|
|
1315
|
+
"text": {"content": "Starting work on this task today."}
|
|
1316
|
+
}
|
|
1317
|
+
]
|
|
1318
|
+
)
|
|
1319
|
+
|
|
1320
|
+
# 5. Query all high priority tasks
|
|
1321
|
+
high_priority_tasks = notion.databases.query(
|
|
1322
|
+
database_id=database["id"],
|
|
1323
|
+
filter={
|
|
1324
|
+
"property": "Priority",
|
|
1325
|
+
"select": {
|
|
1326
|
+
"equals": "High"
|
|
1327
|
+
}
|
|
1328
|
+
},
|
|
1329
|
+
sorts=[
|
|
1330
|
+
{
|
|
1331
|
+
"property": "Due Date",
|
|
1332
|
+
"direction": "ascending"
|
|
1333
|
+
}
|
|
1334
|
+
]
|
|
1335
|
+
)
|
|
1336
|
+
|
|
1337
|
+
print(f"High priority tasks: {len(high_priority_tasks['results'])}")
|
|
1338
|
+
|
|
1339
|
+
# 6. Update task status
|
|
1340
|
+
notion.pages.update(
|
|
1341
|
+
page_id=task["id"],
|
|
1342
|
+
properties={
|
|
1343
|
+
"Status": {
|
|
1344
|
+
"status": {"name": "Completed"}
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
)
|
|
1348
|
+
|
|
1349
|
+
print("Task marked as completed")
|
|
1350
|
+
|
|
1351
|
+
# Run the example
|
|
1352
|
+
if __name__ == "__main__":
|
|
1353
|
+
create_task_management_system()
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1356
|
+
## Async Example
|
|
1357
|
+
|
|
1358
|
+
```python
|
|
1359
|
+
import os
|
|
1360
|
+
import asyncio
|
|
1361
|
+
from notion_client import AsyncClient
|
|
1362
|
+
|
|
1363
|
+
async_notion = AsyncClient(auth=os.environ["NOTION_TOKEN"])
|
|
1364
|
+
|
|
1365
|
+
async def async_example():
|
|
1366
|
+
# List users
|
|
1367
|
+
users = await async_notion.users.list()
|
|
1368
|
+
print(f"Found {len(users['results'])} users")
|
|
1369
|
+
|
|
1370
|
+
# Create a page
|
|
1371
|
+
page = await async_notion.pages.create(
|
|
1372
|
+
parent={"page_id": "parent-page-id"},
|
|
1373
|
+
properties={
|
|
1374
|
+
"title": {
|
|
1375
|
+
"title": [{"text": {"content": "Async Page"}}]
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
)
|
|
1379
|
+
|
|
1380
|
+
# Query a database
|
|
1381
|
+
results = await async_notion.databases.query(
|
|
1382
|
+
database_id="database-id"
|
|
1383
|
+
)
|
|
1384
|
+
|
|
1385
|
+
return results
|
|
1386
|
+
|
|
1387
|
+
# Run async code
|
|
1388
|
+
if __name__ == "__main__":
|
|
1389
|
+
asyncio.run(async_example())
|
|
1390
|
+
```
|
|
1391
|
+
|
|
1392
|
+
## Useful Links
|
|
1393
|
+
|
|
1394
|
+
- Documentation: https://developers.notion.com/
|
|
1395
|
+
- API Reference: https://developers.notion.com/reference/
|
|
1396
|
+
- SDK Repository: https://github.com/ramnes/notion-sdk-py
|
|
1397
|
+
- SDK Documentation: https://ramnes.github.io/notion-sdk-py/
|
|
1398
|
+
- PyPI Package: https://pypi.org/project/notion-client/
|
|
1399
|
+
- Create Integration: https://www.notion.com/my-integrations
|
|
1400
|
+
- Community: Notion Developers Slack
|