How to work with the Notion API in Python
Guide on how to work with the Notion API in Python and automate database editing.
Learn how to work with the Notion API in Python. In this guide we go over:
- How to set up the Notion API
- How to set up the Python code
- How to create database entries
- How to query the database
- How to update database entries
- And how to delete entries.
#more
Setting up the Notion API and a Database¶
First, let's create a full page database in our Notion board. In this tutorial I use a real example from one of my own databases that automatically stores my blog posts whenever I publish a new one. The database has the fields URL
, Title
, and Published
, and demonstates how to edit text and date fields:
Next, follow the official guide to Create a Notion Integration. Following all steps in this page you will:
- Create an integration and get a Token
- Share your database with your integration
- Save the database ID
Now we are ready to automate things in this database with create, read, update, and delete functions.
Set up the Python code¶
To work with the API, we work with the requests
module. We can install it with pip:
pip install requests
Define your token, database ID, and the headers like this. You can find the latest Notion version in the official docs.
import requests
NOTION_TOKEN = "YOUR_INTEGRATION_TOKEN"
DATABASE_ID = "YOUR_DATABASE_ID"
headers = {
"Authorization": "Bearer " + NOTION_TOKEN,
"Content-Type": "application/json",
"Notion-Version": "2022-06-28",
}
Creating pages in your Notion database¶
To create a new page, we send a POST
request:
def create_page(data: dict):
create_url = "https://api.notion.com/v1/pages"
payload = {"parent": {"database_id": DATABASE_ID}, "properties": data}
res = requests.post(create_url, headers=headers, json=payload)
# print(res.status_code)
return res
The corresponding data fields have to correspond to your table column names.
The schema might look a bit complicated and differs for different data types (e.g. text, date, boolean etc.). To determine the exact schema, I recommend dumping the data (see next step) and inspecting the JSON file.
In our example, we create data for the URL
, the Title
, and the Published
columns like so:
from datetime import datetime, timezone
title = "Test Title"
description = "Test Description"
published_date = datetime.now().astimezone(timezone.utc).isoformat()
data = {
"URL": {"title": [{"text": {"content": description}}]},
"Title": {"rich_text": [{"text": {"content": title}}]},
"Published": {"date": {"start": published_date, "end": None}}
}
create_page(data)
Querying Notion database and reading pages¶
To query your database and read all entries, we can use the following function. It uses pagination to retrieve all entries:
def get_pages(num_pages=None):
"""
If num_pages is None, get all pages, otherwise just the defined number.
"""
url = f"https://api.notion.com/v1/databases/{DATABASE_ID}/query"
get_all = num_pages is None
page_size = 100 if get_all else num_pages
payload = {"page_size": page_size}
response = requests.post(url, json=payload, headers=headers)
data = response.json()
# Comment this out to dump all data to a file
# import json
# with open('db.json', 'w', encoding='utf8') as f:
# json.dump(data, f, ensure_ascii=False, indent=4)
results = data["results"]
while data["has_more"] and get_all:
payload = {"page_size": page_size, "start_cursor": data["next_cursor"]}
url = f"https://api.notion.com/v1/databases/{DATABASE_ID}/query"
response = requests.post(url, json=payload, headers=headers)
data = response.json()
results.extend(data["results"])
return results
Then we can retrieve all pages, iterate over them, and access the different fields:
pages = get_pages()
for page in pages:
page_id = page["id"]
props = page["properties"]
url = props["URL"]["title"][0]["text"]["content"]
title = props["Title"]["rich_text"][0]["text"]["content"]
published = props["Published"]["date"]["start"]
published = datetime.fromisoformat(published)
Updating pages in your Notion databse¶
To update a page, we have to send a PATCH
request:
def update_page(page_id: str, data: dict):
url = f"https://api.notion.com/v1/pages/{page_id}"
payload = {"properties": data}
res = requests.patch(url, json=payload, headers=headers)
return res
For example, if we want to update the Published
field, we send the following data. It is the same schema as for creating the page:
page_id = "the page id"
new_date = datetime(2023, 1, 15).astimezone(timezone.utc).isoformat()
update_data = {"Published": {"date": {"start": new_date, "end": None}}}
update_page(page_id, update_data)
Deleting pages in your Notion database¶
Deleting a page is achieved with the same endpoint as for updating the page, but here we set the archived
parameter to True
:
def delete_page(page_id: str):
url = f"https://api.notion.com/v1/pages/{page_id}"
payload = {"archived": True}
res = requests.patch(url, json=payload, headers=headers)
return res
Further references¶
And that's it. To learn more, you can check out the following official Notion links:
FREE VS Code / PyCharm Extensions I Use
✅ Write cleaner code with Sourcery, instant refactoring suggestions: Link*
Python Problem-Solving Bootcamp
🚀 Solve 42 programming puzzles over the course of 21 days: Link*