- Setting Up the Notion API
- Checking the Database’s Properties
- Adding a Page
- Adding Blocks to the Page
- The Final Script
- References
With Notion’s API, we can now hook up other applications to Notion—including Python scripts. However, it requires a bit of setting up.
So here’s a guide on how you can create a Notion page in a database using Python! (Or you can scroll down to the end to just copy the script.)
Setting Up the Notion API
To use the Notion API, we first need to get an API token. Notion calls it an “Internal Integration Secret”.
- Go to Notion’s integrations page.
- Click on “New integration”.
- Fill in the “Basic Information” form.
- Copy the Internal Integration Secret.
You now have the Internal Integration Secret of your new integration, which you can paste into your Python script later.
But this integration will not have access to your whole workspace. To give it access to a database:
- Open your Notion database in the Notion app or browser.
- Click on the three dots on the top right.
- Click on “Add connections”.
- Click on your integration and click “Confirm”.
You can now access this database via the Notion API.
Checking the Database’s Properties
If we want to add page properties to the pages we create, we need to find out what properties the database has. First, make sure that the database has at least one page.
Here is the first Python script we are going to use, which will check the database’s properties:
import requests
NOTION_TOKEN = "XXX" # Find your token here: https://www.notion.so/my-integrations
DATABASE_ID = "XXX" # Database ID for your database, like "e7bd26c59e084e0bbaab0045939e7a81" in https://www.notion.so/sarahmakmq-tutorials/e7bd26c59e084e0bbaab0045939e7a81?v=716517a8f10848268ab7a0f8c572429f
headers = {
"Authorization": "Bearer " + NOTION_TOKEN,
"Content-Type": "application/json",
"Notion-Version": "2022-06-28", # Check what is the latest version here: https://developers.notion.com/reference/changes-by-version
}
def get_pages(num_pages=None):
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()
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
pages = get_pages()
for page in pages:
page_id = page["id"]
props = page["properties"]
print(props)
exit()
Replace
XXX
inNOTION_TOKEN
with your integration’s Internal Integration Secret.Replace
XXX
inDATABASE_ID
with your Notion database ID.You can find the database ID in the URL to your database. For example, in the URL
https://www.notion.so/example/<long_hash_1>?v=<long_hash_2>
, the database ID is<long_hash_1>
.Let’s use this database as an example. It has the database URL
https://www.notion.so/sarahmakmq-tutorials/e7bd26c59e084e0bbaab0045939e7a81?v=716517a8f10848268ab7a0f8c572429f
, so the database ID ise7bd26c59e084e0bbaab0045939e7a81
.Run the script. It should print out something like this:
{'Type': {'id': '~J%60%3E', 'type': 'select', 'select': {'id': '91313987-a4c0-4109-8a7b-99c65733f4ab', 'name': 'Electric', 'color': 'yellow'}}, 'Name': {'id': 'title', 'type': 'title', 'title': [{'type': 'text', 'text': {'content': 'Pikachu', 'link': None}, 'annotations': {'bold': False, 'italic': False, 'strikethrough': False, 'underline': False, 'code': False, 'color': 'default'}, 'plain_text': 'Pikachu', 'href': None}]}}
It looks messy, so let’s make it more readable. You can format it in your preferred code editor, or on js-beautify online. Here is the beautified text:
{ "Type": { "id": "~J%60%3E", "type": "select", "select": { "id": "91313987-a4c0-4109-8a7b-99c65733f4ab", "name": "Electric", "color": "yellow" } }, "Name": { "id": "title", "type": "title", "title": [ { "type": "text", "text": { "content": "Pikachu", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "Pikachu", "href": null } ] } }
We can see that there is a title
property and a select
property, and we know what options we can fill when we add these properties.
So now we can add these properties to our new page. (We can omit any of these properties too, but those property fields would be blank.)
Adding a Page
This is the next script we will use, which will add a new page to the database, and add blocks inside the page.
import requests
NOTION_TOKEN = "XXX" # Find your token here: https://www.notion.so/my-integrations
DATABASE_ID = "XXX" # Database ID for your database, like "e7bd26c59e084e0bbaab0045939e7a81" in https://www.notion.so/sarahmakmq-tutorials/e7bd26c59e084e0bbaab0045939e7a81?v=716517a8f10848268ab7a0f8c572429f
headers = {
"Authorization": "Bearer " + NOTION_TOKEN,
"Content-Type": "application/json",
"Notion-Version": "2022-06-28", # Check what is the latest version here: https://developers.notion.com/reference/changes-by-version
}
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)
if res.status_code == 200:
print(f"{res.status_code}: Page created successfully")
else:
print(f"{res.status_code}: Error during page creation")
return res
properties = XXX
response = create_page(properties)
page_block_id = response.json()["id"]
def edit_page(page_block_id, data: dict):
edit_url = f"https://api.notion.com/v1/blocks/{page_block_id}/children"
payload = data
res = requests.patch(edit_url, headers=headers, json=payload)
if res.status_code == 200:
print(f"{res.status_code}: Page edited successfully")
else:
print(f"{res.status_code}: Error during page editing")
return res
blocks = {"children": []}
edit_page(page_block_id, blocks)
We will fill up the properties
and blocks
variables in the next sections.
To start:
Change the
NOTION_TOKEN
andDATABASE_ID
to your desired values.Replace
XXX
inproperties
with the printed output of your first script.In our example, this was the output of the first script:
{ "Type": { "id": "~J%60%3E", "type": "select", "select": { "id": "91313987-a4c0-4109-8a7b-99c65733f4ab", "name": "Electric", "color": "yellow" } }, "Name": { "id": "title", "type": "title", "title": [ { "type": "text", "text": { "content": "Pikachu", "link": null }, "annotations": { "bold": false, "italic": false, "strikethrough": false, "underline": false, "code": false, "color": "default" }, "plain_text": "Pikachu", "href": null } ] } }
So the
properties
value will look like this:properties = { "Type": { "id": "~J%60%3E", "type": "select", "select": { "id": "91313987-a4c0-4109-8a7b-99c65733f4ab", "name": "Electric", "color": "yellow", }, }, "Name": { "id": "title", "type": "title", "title": [ { "type": "text", "text": {"content": "Pikachu", "link": None}, "annotations": { "bold": False, "italic": False, "strikethrough": False, "underline": False, "code": False, "color": "default", }, "plain_text": "Pikachu", "href": None, } ], }, }
Assign variables to the fields of the properties you want to adjust.
The properties above are the same as an existing page in your database, but we will probably want to change the properties for each page.
Let’s start with editing the text field in the title property—so we can change the title of the page.
To edit the title with a Python variable, replace the string in
"content"
and"plain_text"
with the variable."text": {"content": "Pikachu", "link": None}
Let’s call this variable
title
."text": {"content": title, "link": None}
Next, assign a value to the variable the top of the script.
For our example, we’ll assign the string
"Bulbasaur"
ourtitle
variable:title = "Bulbasaur"
Edit the fields of each property, and add Python variables for the fields you want to adjust. This is the list of database properties.
If your property has the
id
andcolor
fields (such asmulti_select
,select
, andstatus
), remove these two fields."Type": { "id": "~J%60%3E", "type": "select", "select": { "id": "91313987-a4c0-4109-8a7b-99c65733f4ab", "name": "Electric", "color": "yellow", }, }
"Type": { "id": "~J%60%3E", "type": "select", "select": { "name": "Electric", }, }
Note that some properties cannot be edited in the API, so you need to remove them from the
properties
variable. Currently, these properties arerollup
,created_by
,created_time
,last_edited_by
, andlast_edited_time
. See Notion’s API wiki for the updated list of properties that cannot be edited.
Adding Blocks to the Page
So far, the script allows us to add a page (with its properties) to the database. To add blocks to the page, we need to adjust the blocks
variable in the script.
blocks = {"children": []}
To add blocks to the page, we need to add the fields each blocks needs, and fill up the blocks
variable accordingly. See this page to learn about each block type and the fields they need.
If we want to add a text block, we can add the text block’s fields like so:
blocks = {
"children": [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": text_content,
},
}
]
},
},
]
}
Then we need to assign a value to the variable text_content
earlier in the script.
text_content = "Bulbasaur is a small, quadrupedal amphibian Pokémon that has blue-green skin with darker patches."
However, there is a potential issue—Notion’s API has character limits (which you can learn about here), so to be safe, we need to handle this somehow, like splitting text into chunks that are under 2000 characters.
chunks = re.findall(r".{1,2000}(?=\s|$)", text_content)
blocks = {
"children": [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": chunk.strip(),
},
}
]
},
}
for chunk in chunks
]
}
The Final Script
For our example, this is what the final script could look like:
import requests
import re
NOTION_TOKEN = "XXX" # Find your token here: https://www.notion.so/my-integrations
DATABASE_ID = "XXX" # Database ID for your database
title = "Bulbasaur"
text_content = "Bulbasaur is a small, quadrupedal amphibian Pokémon that has blue-green skin with darker patches."
type_text = "Grass"
headers = {
"Authorization": "Bearer " + NOTION_TOKEN,
"Content-Type": "application/json",
"Notion-Version": "2022-06-28", # Check the latest version here: https://developers.notion.com/reference/changes-by-version
}
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)
if res.status_code == 200:
print(f"{res.status_code}: Page created successfully")
else:
print(f"{res.status_code}: Error during page creation")
return res
properties = {
"Type": {
"id": "~J%60%3E",
"type": "select",
"select": {
"name": type_text,
},
},
"Name": {
"id": "title",
"type": "title",
"title": [
{
"type": "text",
"text": {"content": title, "link": None},
"annotations": {
"bold": False,
"italic": False,
"strikethrough": False,
"underline": False,
"code": False,
"color": "default",
},
"plain_text": title,
"href": None,
}
],
},
}
response = create_page(properties)
page_block_id = response.json()["id"]
def edit_page(page_block_id, data: dict):
edit_url = f"https://api.notion.com/v1/blocks/{page_block_id}/children"
res = requests.patch(edit_url, headers=headers, json=data)
if res.status_code == 200:
print(f"{res.status_code}: Page edited successfully")
else:
print(f"{res.status_code}: Error during page editing")
return res
chunks = re.findall(r".{1,2000}(?=\s|$)", text_content)
blocks = {
"children": [
{
"object": "block",
"type": "paragraph",
"paragraph": {
"rich_text": [
{
"type": "text",
"text": {
"content": chunk.strip(),
},
}
]
},
}
for chunk in chunks
]
}
edit_page(page_block_id, blocks)
Hence, this script adds a page like this. It’s titled “Bulbasaur”, and its Type property is “Grass”. In the page, there is one text block with the text “Bulbasaur is a small, quadrupedal amphibian Pokémon that has blue-green skin with darker patches.” Perfect!
With a script like this, you can now use Python to easily add pages to Notion!