
notion-sdk-py is a simple and easy to use client library for the official Notion API.
It is meant to be a Python version of the reference JavaScript SDK, so usage should be very similar between both. 😊 (If not, please open an issue or PR!)
Installation
pip install notion-client
Usage
Use Notion's Getting Started Guide to get set up to use Notion's API.
Import and initialize a client using an integration token or an OAuth access token.
import os
from notion_client import Client
notion = Client(auth=os.environ["NOTION_TOKEN"])
In an asyncio environment, use the asynchronous client instead:
from notion_client import AsyncClient
notion = AsyncClient(auth=os.environ["NOTION_TOKEN"])
Make a request to any Notion API endpoint.
from pprint import pprint
list_users_response = notion.users.list()
pprint(list_users_response)
[!NOTE] See the complete list of endpoints in the API reference.
or with the asynchronous client:
list_users_response = await notion.users.list()
pprint(list_users_response)
This would output something like:
{'results': [{'avatar_url': 'https://secure.notion-static.com/e6a352a8-8381-44d0-a1dc-9ed80e62b53d.jpg',
'id': 'd40e767c-d7af-4b18-a86d-55c61f1e39a4',
'name': 'Avocado Lovelace',
'object': 'user',
'person': {'email': '[email protected]'},
'type': 'person'},
...]}
All API endpoints are available in both the synchronous and asynchronous clients.
Endpoint parameters are grouped into a single object. You don't need to remember which parameters go in the path, query, or body.
my_page = notion.data_sources.query(
**{
"data_source_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
"filter": {
"property": "Landmark",
"rich_text": {
"contains": "Bridge",
},
},
}
)
Handling errors
If the API returns an unsuccessful response, an APIResponseError will be raised.
The error contains properties from the response, and the most helpful is code.
You can compare code to the values in the APIErrorCode object to avoid
misspelling error codes.
import logging
from notion_client import APIErrorCode, APIResponseError, Client
try:
notion = Client(auth=os.environ["NOTION_TOKEN"])
my_page = notion.data_sources.query(
**{
"data_source_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
"filter": {
"property": "Landmark",
"rich_text": {
"contains": "Bridge",
},
},
}
)
except APIResponseError as error:
if error.code == APIErrorCode.ObjectNotFound:
#
# For example: handle by asking the user to select a different data source
#
...
else:
# Other error handling code
print(error)
Logging
The client emits useful information to a logger. By default, it only emits warnings and errors.
If you're debugging an application, and would like the client to log request & response
bodies, set the log_level option to logging.DEBUG.
import logging
from notion_client import Client
notion = Client(
auth=os.environ["NOTION_TOKEN"],
log_level=logging.DEBUG,
)
You may also set a custom logger to emit logs to a destination other than stdout.
Have a look at Python's logging cookbook
if you want to create your own logger.
Client options
Client and AsyncClient both support the following options on initialization.
These options are all keys in the single constructor parameter.
| Option | Default value | Type | Description |
|---|---|---|---|
auth |
None |
string |
Bearer token for authentication. If left undefined, the auth parameter should be set on each request. |
log_level |
logging.WARNING |
int |
Verbosity of logs the instance will produce. By default, logs are written to stdout. |
timeout_ms |
DEFAULT_TIMEOUT_MS |
int |
Number of milliseconds to wait before emitting a RequestTimeoutError |
base_url |
DEFAULT_BASE_URL |
string |
The root URL for sending API requests. This can be changed to test with a mock server. |
logger |
Log to console | logging.Logger |
A custom logger. |
retry |
See constants | RetryOptions |
Configuration for automatic retries on rate limits (429), service overloads (529), and server errors (500, 503). See Automatic retries below. |
Automatic retries
The client automatically retries requests that fail due to rate limiting or transient server errors. By default, it will retry up to 2 times using exponential back-off with jitter.
Retryable errors:
rate_limited(HTTP 429) - Too many requests; retried for all HTTP methodsservice_overload(HTTP 529) - Service overloaded; retried for all HTTP methodsinternal_server_error(HTTP 500) - Server error; retried only for GET and DELETEservice_unavailable(HTTP 503) - Service temporarily unavailable; retried only for GET and DELETE
Server errors (500, 503) are only retried for idempotent HTTP methods (GET, DELETE) to avoid duplicate side effects. Rate limits (429) and service overloads (529) are retried for all methods since the server explicitly asks clients to retry.
Configuration:
from notion_client import Client, RetryOptions
notion = Client(
auth="secret_...",
retry=RetryOptions(
max_retries=5, # Maximum retry attempts (default: 2)
initial_retry_delay_ms=500, # Initial delay in ms (default: 1000)
max_retry_delay_ms=60000, # Maximum delay in ms (default: 60000)
),
)
To disable automatic retries:
notion = Client(auth="secret_...", retry=False)
Constants
The SDK exports named constants for all default values used by the client, as well as useful Notion-specific values. You can import them directly:
from notion_client