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!)
📢 Announcement (28-12-2023) — Release 2.2.1 is out and fixes iteration helpers.
What's new in 2.2.0 (26-12-2023):
- Icons and covers can now be removed from pages.
filter_properties
has been added tonotion.pages.retrieve
.- You can now pass your own
start_cursor
in the iteration helpers.
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.
See the complete list of endpoints in the API reference.
from pprint import pprint
list_users_response = notion.users.list()
pprint(list_users_response)
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': 'avo@example.org'},
'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.databases.query(
**{
"database_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
try:
my_page = notion.databases.query(
**{
"database_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 database
else:
# Other error handling code
logging.error(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
.
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 |
60_000 |
int |
Number of milliseconds to wait before emitting a RequestTimeoutError |
base_url |
"https://api.notion.com" |
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. |
Full API responses
The following functions can distinguish between full and partial API responses.
Function | Purpose |
---|---|
is_full_page |
Determine whether an object is a full Page object |
is_full_block |
Determine whether an object is a full Block object |
is_full_database |
Determine whether an object is a full Database object |
is_full_page_or_database |
Determine whether an object is a full Page object or Database object |
is_full_user |
Determine whether an object is a full User object |
is_full_comment |
Determine whether an object is a full Comment object |
from notion_client.helpers import is_full_page
full_or_partial_pages = await notion.databases.query(
database_id="897e5a76-ae52-4b48-9fdf-e71f5945d1af"
)
for page in full_or_partial_pages["results"]:
if not is_full_page_or_database(page):
continue
print(f"Created at: {page['created_time']}")
Utility functions
These functions can be helpful for dealing with any of the paginated APIs.
iterate_paginated_api(function, **kwargs)
and its async version
async_iterate_paginated_api(function, **kwargs)
turn any paginated API into a generator.
The function
parameter must accept a start_cursor
argument. Example: notion.blocks.children.list
.
from notion_client.helpers import iterate_paginated_api
for block in iterate_paginated_api(
notion.databases.query, database_id="897e5a76-ae52-4b48-9fdf-e71f5945d1af"
):
# Do something with block.
...
If you don't need a generator, collect_paginated_api(function, **kwargs)
and
its async version async_collect_paginated_api(function, **kwargs)
have the
same behavior than the previous functions, but return a list of all results
from the paginated API.
from notion_client.helpers import collect_paginated_api
all_results = collect_paginated_api(
notion.databases.query, database_id="897e5a76-ae52-4b48-9fdf-e71f5945d1af"
)
Testing
Run the tests with the pytest
command. If you want to test against all Python
versions, you can run tox
instead.
The tests are using pytest-vcr
's cassettes for simulating requests to the
Notion API. To create new tests or run them without cassettes, you need to set
up the environment variables NOTION_TOKEN
and NOTION_TEST_PAGE_ID
(a page
where your integration has all the capabilities enabled).
The code will use the page at NOTION_TEST_PAGE_ID
to generate a temporary
environment with the Notion objects to be tested, which will be deleted
at the end of the session.
Requirements
This package supports the following minimum versions:
- Python >= 3.7
- httpx >= 0.15.0
Earlier versions may still work, but we encourage people building new applications to upgrade to the current stable.
Getting help
If you want to submit a feature request for Notion's API, or are experiencing
any issues with the API platform, please email developers@makenotion.com
.
If you found a bug with the library, please submit an issue.