DEV Community

Cover image for How to use Python with Notion API
Mihai-Adrian Andrei
Mihai-Adrian Andrei

Posted on

How to use Python with Notion API

Everybody uses Notion. And why not? It is an awesome tool. But what if you want to also add it to some of your apps? It seems you can now do it by using the Notion API and I will show how you can integrate it using Python.

Notion setup

First, you need to create a page that contains a database in Notion. In this example, we are going to make one that contains 3 fields: name, genre, and completed.

image.png

In order to have access to this page inside Python, we need to create an integration for it. For that, you can go to Settings => Integrations => Develop your own integrations. After that, you specify a name for your integration and click submit. In the end, you will get to this screen:

image.png

As you can see in the photo, you now have a secret key. Copy that because we will need it in our Python program.

We need to do 2 more steps in Notion before starting to write some code:

  • We need to go on the notion page, click the Share button, press Invite, and then you can select the integration that you just created from a list:

image.png

  • With the page opened in your browser, you will need a database id. Let's say the link is the following one: https://www.notion.so/19f00145217c4437afb06cfdbb2ad994?v=51972570a71c4b8b9b1feeec01e87eb5. The database id is 19f00145217c4437afb06cfdbb2ad994.

Python Setup

First, we import the requests library that we are going to use to interact with the Notion API. Then, we store the secret and database_id from the notion setup.

import json
import requests

token = 'secret_from_notion_integration'
database_id = 'database_id_from_link'
Enter fullscreen mode Exit fullscreen mode

Next, we will use the requests library to interact with the Notion API.

The first function we are going to create is getMovies.

def getMovies():
  url = f'https://api.notion.com/v1/databases/{database_id}/query'

  r = requests.post(url, headers={
    "Authorization": f"Bearer {token}",
    "Notion-Version": "2021-08-16"
  })

  result_dict = r.json()
  movie_list_result = result_dict['results']

  print(movie_list_result)

Enter fullscreen mode Exit fullscreen mode

Now, if you add a movie in Notion, and you call this function, you will see a lot of data. In order to make it more readeble and use only the information we need, we will make a helper function:

def mapNotionResultToMovie(result):
  # you can print result here and check the format of the answer.
  movie_id = result['id']
  properties = result['properties']
  genre = properties['Genre']['rich_text'][0]['text']['content']
  name = properties['Name']['title'][0]['text']['content']
  completed = properties['Completed']['checkbox']

  return {
    'genre': genre,
    'name': name,
    'completed': completed,
    'movie_id': movie_id
  }
Enter fullscreen mode Exit fullscreen mode

And call it inside getMovies. The function should contain the following code:

def getMovies():
  url = f'https://api.notion.com/v1/databases/{database_id}/query'

  r = requests.post(url, headers={
    "Authorization": f"Bearer {token}",
    "Notion-Version": "2021-08-16"
  })

  result_dict = r.json()
  movie_list_result = result_dict['results']

  movies = []

  for movie in movie_list_result:

    movie_dict = mapNotionResultToMovie(movie)
    movies.append(movie_dict)

  return movies

Enter fullscreen mode Exit fullscreen mode

Example of usage:

movies = getMovies()
# json.dumps is used to pretty print a dictionary 
print('Movie list:', json.dumps(movies, indent=2))
Enter fullscreen mode Exit fullscreen mode

Now, you can use this function to display your movies inside Python. Pretty cool, right 😁 ?

The next function we are going to implement is createMovie. For this one, we will need to construct a payload similar to the response from getMovies.

def createMovie(name, genre, completed=False):
  url = f'https://api.notion.com/v1/pages'

  payload = {
    "parent": {
      "database_id": database_id
    },
    "properties": {
      "Name": {
        "title": [
          {
            "text": {
              "content": name
            }
          }
        ]
      },
      "Genre": {
        "rich_text": [
          {
            "text": {
              "content": genre
            }
          }
        ]
      },
      "Completed": {
        "checkbox": completed
      }
    }}

  r = requests.post(url, headers={
    "Authorization": f"Bearer {token}",
    "Notion-Version": "2021-08-16",
    "Content-Type": "application/json"
  }, data=json.dumps(payload))

  movie = mapNotionResultToMovie(r.json())
  return movie

Enter fullscreen mode Exit fullscreen mode

You can use it like this:

createdMovie = createMovie('Movie1', 'Genre1', False)

print('Created Movie:', json.dumps(createdMovie, indent=2))
Enter fullscreen mode Exit fullscreen mode

If you check Notion, you will see that a new entry in the table was created.πŸŽ‰πŸŽ‰πŸŽ‰

The update function is pretty similar to the create one. The major difference is that we need to also take into consideration a movieId. We create the payload in a similar way, but we also add the movieId in the URL.

def updateMovie(movieId, movie):
  url = f'https://api.notion.com/v1/pages/{movieId}'

  payload = {
    "properties": {
      "Name": {
        "title": [
          {
            "text": {
              "content": movie['name']
            }
          }
        ]
      },
      "Genre": {
        "rich_text": [
          {
            "text": {
              "content": movie['genre']
            }
          }
        ]
      },
      "Completed": {
        "checkbox": movie['completed']
      }
    }}

  r = requests.patch(url, headers={
    "Authorization": f"Bearer {token}",
    "Notion-Version": "2021-08-16",
    "Content-Type": "application/json"
  }, data=json.dumps(payload))

  movie = mapNotionResultToMovie(r.json())
  return movie
Enter fullscreen mode Exit fullscreen mode

In order to use this function, you first need to call getMovies(). In that response, you can get a movieId (in the ex: fdd0fa87-4729-43e6-ae3f-823d48b382ee) and use it like this:

updatedMovie = updateMovie('fdd0fa87-4729-43e6-ae3f-823d48b382ee', {
  'name': 'UpdatedMovie1',
  'genre': 'UpdatedGenre1',
  'completed': True
})
print('Update movie', json.dumps(updatedMovie, indent=2))

Enter fullscreen mode Exit fullscreen mode

The last function that we are going to create is deleteMovie. In Notion, pages are using a property called archived. If we set that to true, then the page will be deleted. So, this function will use the update endpoint in order to change the value of the 'archived' boolean.

def deleteMovie(movieId):
  url = f'https://api.notion.com/v1/pages/{movieId}'

  payload = {
    "archived": True
  }

  r = requests.patch(url, headers={
    "Authorization": f"Bearer {token}",
    "Notion-Version": "2021-08-16",
    "Content-Type": "application/json"
  }, data=json.dumps(payload))
Enter fullscreen mode Exit fullscreen mode

Now, you can use it with a movieId and if you check the database in Notion, that specific row will be deleted.

deleteMovie('a19e538d-10cc-40ec-91bb-f7237c93e428')
Enter fullscreen mode Exit fullscreen mode

It is easier to interact with Notion from JavaScript because they provide a client, and in Python, we don't have one, but that shouldn't stop you to use it😁.

Discussion (3)

Collapse
ivanms1 profile image
Ivan

Good stuff!

Collapse
itbj profile image
itbj00

Good stuff!

Collapse
itbj profile image
itbj00