Skip to content

Quick Start

Using Notional requires an understanding of concepts described in the Notion API. In particular, it is important to understand authorization and the data model.

Authorization

Obtain an authentication token from your Notion account.

Token Security

It is generally a best practice to read the auth token from an environment variable or a secrets file. To prevent accidental exposure, it is NOT recommended to save the token in source.

Installation

Install the most recent release using PyPI:

pip install notional

Note: it is recommended to use a virtual environment (venv) for installing libraries to prevent conflicting dependency versions.

Connect

Connect to the API using an integration token or an OAuth access token:

import notional

notion = notional.connect(auth=AUTH_TOKEN)

Data Objects

The majority of the Notion API expresses capabilities through data objects that follow a specific pattern. It is good to be familiar with the Notion API representation of these objects, as it will help understand concepts found in Notional.

Many common uses of data objects require interacting with the internal data. Notional provides two helper methods for working with this structure: compose and call.

Constructing

Constructing a data object requires manually setting up the internal data structures. Consider the following example:

text = "It was a dark and stormy night..."
nested = TextObject.NestedData(content=text)
rtf = text.TextObject(text=nested, plain_text=text)
content = blocks.Paragraph.NestedData(text=[rtf])
para = blocks.Paragraph(paragraph=content)

Notice how we build the NestedData object in order to construct the final Paragraph. This approach provides the most versatility when building complex objects.

Technical note: since Notional uses pydantic for object serialization under the hood, the constructor for each object is generated based on the object properties.

Composing

Composing a data object provides the caller a shorthand to construction. Rather than explicitly laying out the nested data, the __compose__ method takes care of setting up the internal data structure.

Consider our example from above. Using the composable feature of a Paragraph block changes the code like so:

para = blocks.Paragraph["It was a dark and stormy night..."]

Note the use of [ ] in the composition example... This instructs the Paragraph to compose itself from the given parameters. The acceptable parameters for this method is specific to the object being composed.

Technical note: since the constructor is provided by pydantic, we do not override it. Instead, we have chosen to provide an alternate form of creating objects. We refer to this form as "composing" from basic types.

Calling

Calling a data object provides access to the underlying data structure, which typically contains the content of the object.

For example, to get the "checked" state of a ToDo block, we can use either the nested data structure directly or call the block:

todo = blocks.ToDo(...)

# direct access
checked = todo.to_do.checked

# nested data access
checked = todo().checked

# nested property access
checked = todo("checked")

In the above example, all three approaches for getting the checked field of our ToDo block produce the same result.