How to use Python with Notion API
Tags: python, notion
Published: 2022-01-06 14:31:36

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](https://cdn.hashnode.com/res/hashnode/image/upload/v1641454499743/26O5x4__I.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](https://cdn.hashnode.com/res/hashnode/image/upload/v1641454720564/wHtL1V_hv.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](https://cdn.hashnode.com/res/hashnode/image/upload/v1641454890420/AWKuYAkLc.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.
```py
import json
import requests

token = 'secret_from_notion_integration'
database_id = 'database_id_from_link'
```
Next, we will use the requests library to interact with the Notion API.

The first function we are going to create is `getMovies`.

```py
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)

```

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:
```py
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
  }
```
And call it inside `getMovies`. The function should contain the following code:
```py
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

```

Example of usage:
```py
movies = getMovies()
# json.dumps is used to pretty print a dictionary 
print('Movie list:', json.dumps(movies, indent=2))
```

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`. 

```py
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

```

You can use it like this:

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

print('Created Movie:', json.dumps(createdMovie, indent=2))
```

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.

```py
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
```

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:
```py
updatedMovie = updateMovie('fdd0fa87-4729-43e6-ae3f-823d48b382ee', {
  'name': 'UpdatedMovie1',
  'genre': 'UpdatedGenre1',
  'completed': True
})
print('Update movie', json.dumps(updatedMovie, indent=2))

```

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.

```py
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))
```

Now, you can use it with a `movieId` and if you check the database in Notion, that specific row will be deleted.
```py
deleteMovie('a19e538d-10cc-40ec-91bb-f7237c93e428')
```

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😁.