Skip to content

database

notion.database

API for exchanging information with Notion database. Main features include, 1) creating a notion database with property assignments. 2) adding dictionary data to existing notion database.

PROPERTIES module-attribute

PROPERTIES = {}

RESEARCH_API_PATH module-attribute

RESEARCH_API_PATH = 'http://data.saige.in:8000/workspaces/notion/research_api_token.txt'

FieldType module-attribute

FieldType = Dict[str, str]

RESPONSE_SUCCESS module-attribute

RESPONSE_SUCCESS = 200

QUERY_PAGE_SIZE module-attribute

QUERY_PAGE_SIZE = 100

BasicProperty

BasicProperty(value, **kwargs)

Notion database basic properties are implemented. It converts values into property object structures specified by the notion api. Additionally, it can check whether given value is valid for the property. Note that status property is not implemented due to the limited notion api capabilites.

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

value instance-attribute

value = value

__init_subclass__

__init_subclass__(**kwargs)
Source code in ResearchToolkit/notion/property.py
def __init_subclass__(cls, **kwargs):
    super().__init_subclass__(**kwargs)
    name = pascal_to_snake(cls.__name__)
    cls.name = (
        name.replace("text", "rich_text")
        .replace("person", "people")
        .replace("phone", "phone_number")
    )
    cls.filter_ops = get_avaliable_filter_ops(cls.name)
    register(cls, name)

__call__

__call__()
Source code in ResearchToolkit/notion/property.py
def __call__(self):
    return {self.name: self.value}

get_value classmethod

get_value(property_: dict)

extracts values from a property object structure specified by the notion api. (opposite operation of call method)

Parameters:

  • property_ (dict) –

    property dictionary output of notion api. must include "type" key.

Returns:

  • _type_

    value of given property. ex) 3.14 in above example.

Source code in ResearchToolkit/notion/property.py
@classmethod
def get_value(cls, property_: dict):
    """
    extracts values from a property object structure specified by the notion api.
    (opposite operation of __call__ method)


    Args:
        property_ (dict): property dictionary output of notion api. must include "type" key.
        ex)
        {
            "type": "number",
            "number": 3.14
        }

    Returns:
        _type_: value of given property. ex) 3.14 in above example.
    """
    return property_[property_["type"]]

get_filter classmethod

get_filter(property_name, filter_op, filter_val)
Source code in ResearchToolkit/notion/property.py
@classmethod
def get_filter(cls, property_name, filter_op, filter_val):
    assert filter_op in cls.filter_ops.keys()
    assert isinstance(filter_val, cls.filter_ops[filter_op])
    return Filter({"property": property_name, f"{cls.name}": {filter_op: filter_val}})

Title

Title(value, **kwargs)

Bases: Text

Source code in ResearchToolkit/notion/property.py
def __init__(self, value, **kwargs):
    self.value = value

use_saige_token_as_default

use_saige_token_as_default(function)
Source code in ResearchToolkit/notion/common.py
def use_saige_token_as_default(function):
    @wraps(function)
    def wrapper(
        token_path: str = RESEARCH_API_PATH,
        token: Optional[str] = None,
        *args,
        **kwargs,
    ):
        if not token:
            token = get_token(token_path)
        return function(token=token, *args, **kwargs)

    return wrapper

get_token

get_token(token_path: str = RESEARCH_API_PATH)
Source code in ResearchToolkit/notion/common.py
def get_token(token_path: str = RESEARCH_API_PATH):
    if "http" in token_path:
        token = urlopen(token_path).read().decode("utf-8")
    else:
        with open(token_path, "r") as file:
            token = file.read()

    return token

convert_data_into_property

convert_data_into_property(data: Dict[str, Any], fields: FieldType)

converts dictionary data into a property form required by notion api. key of data and fields shoud match!

e.g) data = {"exp_name": "cls_base", "accuracy": 0.99} fields = {"exp_name": "title", "accuracy": "number"}

    return:
    {
        "exp_name": {
            "title": [
                "text": {"content": "cls_base"}
            ]
        },
        "accuracy": {
            "number": 0.99
        }
    }

Parameters:

  • data (Dict[str, Any]) –

    key: property name, value: property value

  • fields (FieldType) –

    key: property name, value: property type

Returns:

  • _type_

    property required by notion api

Source code in ResearchToolkit/notion/database.py
def convert_data_into_property(data: Dict[str, Any], fields: FieldType):
    """converts dictionary data into a property form required by notion api.
       key of data and fields shoud match!

       e.g) data = {"exp_name": "cls_base", "accuracy": 0.99}
            fields = {"exp_name": "title", "accuracy": "number"}

            return:
            {
                "exp_name": {
                    "title": [
                        "text": {"content": "cls_base"}
                    ]
                },
                "accuracy": {
                    "number": 0.99
                }
            }

    Args:
        data (Dict[str, Any]): key: property name, value: property value
        fields (FieldType): key: property name, value: property type

    Returns:
        _type_: property required by notion api
    """
    properties = {}
    for key, value in data.items():
        if key not in fields:
            print(f"Invalid keys will be ignored: {key}")
            continue

        property_type = fields[key]

        if property_type not in PROPERTIES:
            print(f"property {property_type} not supported")
            continue

        if isinstance(value, dict):
            property_ = PROPERTIES[property_type](**value)
        else:
            property_ = PROPERTIES[property_type](value)

        if not property_:
            print(f"{value} is invalid for {property_type}")
            continue

        properties.update({key: property_()})

    return properties

make_database_property_schema

make_database_property_schema(fields: FieldType, relations: Dict[str, Dict[str, str]] = None) -> Dict

Parameters:

  • fields (FieldType) –

    key: name of the property, value: property type (should be one of the keys in PROPERTIES) e.g) {"exp_name": "title", "accuracy": "number"} create a database whose property names are exp_name, accuracy and their property types are title and number.

  • relations (Dict[str, Dict[str, str]], default: None ) –

    key: name of the relation property, value: dictionary with "database_id" and "type" info. "database_id" is notion database id to relate to "type" should be one of "single_property" or "dual_property". e.g) {"related_task": {"database_id": (database_id), "type": "dual_property}} !NOTE: relation database should also be shared with notion integration! Defaults to None.

Returns:

  • Dict ( Dict ) –

    Notion API database property schema (https://developers.notion.com/reference/property-schema-object)

Source code in ResearchToolkit/notion/database.py
def make_database_property_schema(
    fields: FieldType,
    relations: Dict[str, Dict[str, str]] = None,
) -> Dict:
    """
    Args:
        fields (FieldType): key: name of the property, value: property type (should be one of the keys in `PROPERTIES`)
                                 e.g) {"exp_name": "title", "accuracy": "number"}
                                      create a database whose property names are exp_name, accuracy and their property types are title and number.
        relations (Dict[str, Dict[str, str]], optional): key: name of the relation property, value: dictionary with "database_id" and "type" info.
                                               "database_id" is notion database id to relate to
                                               "type" should be one of "single_property" or "dual_property".
                                               e.g) {"related_task": {"database_id": (database_id), "type": "dual_property}}
                                               !NOTE: relation database should also be shared with notion integration!
                                               Defaults to None.

    Returns:
        Dict: Notion API database property schema (https://developers.notion.com/reference/property-schema-object)
    """
    properties = {
        name: {
            property_.replace("text", "rich_text")
            .replace("person", "people")
            .replace("phone", "phone_number"): {}
        }
        for name, property_ in fields.items()
    }

    for name in properties.keys():
        for property_type in properties[name]:
            if property_type in ["select", "multi_select"]:
                properties[name][property_type] = {"options": []}

    if relations is not None:
        for name, info in relations.items():
            if info["type"] not in ["single_property", "dual_property"]:
                raise ValueError("relation type should be single_property or dual_property")
            properties.update(
                {
                    name: {
                        "relation": {
                            "database_id": info["database_id"],
                            info["type"]: {},
                        }
                    }
                }
            )

    return properties

_add_to_database

_add_to_database(database_id: str, properties: dict, token_path: str = RESEARCH_API_PATH, token: Optional[str] = None)

add a page with properties to the notion database.

Parameters:

  • database_id (str) –

    notion database id to add page.

  • properties (dict) –

    page property dictionary in specific format described in notion api docs. see (https://developers.notion.com/reference/property-value-object). basic format: { "(property_name)":{ "(property_type)": (value whose type and structure are specific to property_type) } } This can be easily obtained by using child classes of BasicProperty. refer 'convert_data_into_property'.

  • token_path (str, default: RESEARCH_API_PATH ) –

    description. Defaults to RESEARCH_API_PATH.

  • token (Optional[str], default: None ) –

    description. Defaults to None.

Returns:

  • _type_

    request response code (200 if succeeded) and response text, page_id (None if request failed)

Source code in ResearchToolkit/notion/database.py
def _add_to_database(
    database_id: str,
    properties: dict,
    token_path: str = RESEARCH_API_PATH,
    token: Optional[str] = None,
):
    """add a page with properties to the notion database.

    Args:
        database_id (str): notion database id to add page.
        properties (dict): page property dictionary in specific format described in notion api docs.
                           see (https://developers.notion.com/reference/property-value-object).
                           basic format:
                           {
                                "(property_name)":{
                                     "(property_type)":
                                        (value whose type and structure are specific to property_type)
                                }
                            }
                           This can be easily obtained by using child classes of `BasicProperty`.
                           refer 'convert_data_into_property'.
        token_path (str, optional): _description_. Defaults to RESEARCH_API_PATH.
        token (Optional[str], optional): _description_. Defaults to None.

    Returns:
        _type_: request response code (200 if succeeded) and response text, page_id (None if request failed)
    """
    if not token:
        token = get_token(token_path)

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "Notion-Version": "2022-06-28",
    }

    api_url = "https://api.notion.com/v1/pages"

    data = {"parent": {"database_id": database_id}, "properties": properties}
    data = json.dumps(data)

    # create database in notion
    response = requests.request("POST", api_url, headers=headers, data=data)

    try:
        page_id = response.json()["id"]
    except AttributeError:
        print("database creation failed")
        page_id = None

    return response.status_code, response.text, page_id

create_database

create_database(page_id: str, fields: FieldType, relations: Dict[str, Dict[str, str]] = {}, title: Optional[str] = None, token_path: str = RESEARCH_API_PATH, token: Optional[str] = None)

creates a notion database in a page_id page. it is recommended to add "user" field in fields which specifies the user of api when collaborating on a database.

Parameters:

  • page_id (str) –

    notion page id

  • fields (FieldType) –

    key: name of the property, value: property type (should be one of the keys in PROPERTIES) e.g) {"exp_name": "title", "accuracy": "number"} create a database whose property names are exp_name, accuracy and their property types are title and number.

  • relations (Dict[str, Dict[str, str]], default: {} ) –

    key: name of the relation property, value: dictionary with "database_id" and "type" info. "database_id" is notion database id to relate to "type" should be one of "single_property" or "dual_property". e.g) {"related_task": {"database_id": (database_id), "type": "dual_property}} !NOTE: relation database should also be shared with notion integration!

  • title (str, default: None ) –

    title of database. Defaults to None ("untitled" database will be created).

  • token_path (str, default: RESEARCH_API_PATH ) –

    description. Defaults to RESEARCH_API_PATH.

  • token (Optional[str], default: None ) –

    description. Defaults to None.

Returns:

  • _type_

    request response code (200 if succeeded), response text, database_id (None if request failed)

Source code in ResearchToolkit/notion/database.py
def create_database(
    page_id: str,
    fields: FieldType,
    relations: Dict[str, Dict[str, str]] = {},
    title: Optional[str] = None,
    token_path: str = RESEARCH_API_PATH,
    token: Optional[str] = None,
):
    """creates a notion database in a page_id page.
       it is recommended to add "user" field in `fields` which specifies the user of api when collaborating on a database.

    Args:
        page_id (str): notion page id
        fields (FieldType): key: name of the property, value: property type (should be one of the keys in `PROPERTIES`)
                                 e.g) {"exp_name": "title", "accuracy": "number"}
                                      create a database whose property names are exp_name, accuracy and their property types are title and number.
        relations (Dict[str, Dict[str, str]]): key: name of the relation property, value: dictionary with "database_id" and "type" info.
                                               "database_id" is notion database id to relate to
                                               "type" should be one of "single_property" or "dual_property".
                                               e.g) {"related_task": {"database_id": (database_id), "type": "dual_property}}
                                               !NOTE: relation database should also be shared with notion integration!
        title (str, optional): title of database. Defaults to None ("untitled" database will be created).
        token_path (str, optional): _description_. Defaults to RESEARCH_API_PATH.
        token (Optional[str], optional): _description_. Defaults to None.

    Returns:
        _type_: request response code (200 if succeeded), response text, database_id (None if request failed)
    """
    if not token:
        token = get_token(token_path)

    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "Notion-Version": "2022-06-28",
    }

    api_url = "https://api.notion.com/v1/databases"

    # define a database
    property_types = fields.values()
    assert "title" in property_types, "title should be in properties"

    properties = make_database_property_schema(fields=fields, relations=relations)

    data = {"parent": {"type": "page_id", "page_id": page_id}, "properties": properties}

    if title:
        data.update(Title(title)())

    data = json.dumps(data)

    # create database in notion
    response = requests.request("POST", api_url, headers=headers, data=data)

    try:
        database_id = response.json()["id"]
    except AttributeError:
        print("database creation failed")
        database_id = None

    return response.status_code, response.text, database_id

retrieve_database_fields

retrieve_database_fields(database_id: str, token_path: str = RESEARCH_API_PATH, token: Optional[str] = None, is_page: bool = False)

retrieves database fields

Parameters:

  • database_id (_type_) –

    notion database id

  • token_path (_type_, default: RESEARCH_API_PATH ) –

    description. Defaults to RESEARCH_API_PATH.

  • token (_type_, default: None ) –

    description. Defaults to None.

  • is_page (bool, default: False ) –

    True if the id is for a page. Defaults to None.

Returns:

  • _type_

    fields dictionary - key: property name, value: property type e.g) {"exp_name": "title", "accuracy": "number"}

Source code in ResearchToolkit/notion/database.py
def retrieve_database_fields(
    database_id: str,
    token_path: str = RESEARCH_API_PATH,
    token: Optional[str] = None,
    is_page: bool = False,
):
    """retrieves database fields

    Args:
        database_id (_type_): notion database id
        token_path (_type_, optional): _description_. Defaults to RESEARCH_API_PATH.
        token (_type_, optional): _description_. Defaults to None.
        is_page (bool): True if the id is for a page. Defaults to None.

    Returns:
        _type_: fields dictionary - key: property name, value: property type
                                      e.g) {"exp_name": "title", "accuracy": "number"}
    """
    if not token:
        token = get_token(token_path)

    headers = {
        "Authorization": f"Bearer {token}",
        "Notion-Version": "2022-06-28",
    }

    sub_url = "pages" if is_page else "databases"
    api_url = f"https://api.notion.com/v1/{sub_url}/{database_id}"

    # get database from notion
    response = requests.get(api_url, headers=headers)

    # extract database fields
    database_fields = {
        name: prop["type"]
        .replace("rich_text", "text")
        .replace("people", "person")
        .replace("phone_number", "phone")
        for name, prop in response.json()["properties"].items()
    }

    return database_fields

add_data_to_database

add_data_to_database(database_id: str, data: dict, token_path: str = RESEARCH_API_PATH, token: Optional[str] = None, user: Optional[Dict[str, BasicProperty]] = None)

add data to notion database. properties of data values are assigned to match the properties of existing database.

when collaborating on a database, it is recommended to use user option to specfiy who edited the database.

Parameters:

  • database_id (str) –

    description

  • data (dict) –

    data to store in database. keys should match names of the database properties

  • token_path (str, default: RESEARCH_API_PATH ) –

    description. Defaults to RESEARCH_API_PATH.

  • token (Optional[str], default: None ) –

    description. Defaults to None.

  • user (Optional[Dict[str, BasicProperty]], default: None ) –
                            use when collaborating on a databaese to specify editor of the database.
                            key should be the property name of the database responsible for tracking api user.
                            if vaule is `Person`, a notification will be send in notion.
    

Returns:

  • _type_

    request response code (200 if succeeded) and response text, page_id (None if request failed)

Source code in ResearchToolkit/notion/database.py
def add_data_to_database(
    database_id: str,
    data: dict,
    token_path: str = RESEARCH_API_PATH,
    token: Optional[str] = None,
    user: Optional[Dict[str, BasicProperty]] = None,
):
    """
    add data to notion database.
    properties of data values are assigned to match the properties of existing database.

    when collaborating on a database, it is recommended to use `user` option to specfiy who edited the database.

    Args:
        database_id (str): _description_
        data (dict): data to store in database. keys should match names of the database properties
        token_path (str, optional): _description_. Defaults to RESEARCH_API_PATH.
        token (Optional[str], optional): _description_. Defaults to None.
        user (Optional[Dict[str, BasicProperty]], optional):
                                        use when collaborating on a databaese to specify editor of the database.
                                        key should be the property name of the database responsible for tracking api user.
                                        if vaule is `Person`, a notification will be send in notion.

    Returns:
        _type_: request response code (200 if succeeded) and response text, page_id (None if request failed)
    """
    database_fields = retrieve_database_fields(database_id, token_path=token_path, token=token)

    properties = convert_data_into_property(data, database_fields)

    if user and list(user.keys())[0] in database_fields:
        properties.update(user)

    return _add_to_database(database_id, properties, token_path=token_path, token=token)

query_database

query_database(database_id: str, token_path: str = RESEARCH_API_PATH, token: Optional[str] = None, request_body: Optional[dict] = None)
query a database.
refer https://developers.notion.com/reference/post-database-query

Parameters:

  • database_id (str) –

    description

  • token_path (str, default: RESEARCH_API_PATH ) –

    description. Defaults to RESEARCH_API_PATH.

  • token (Optional[str], default: None ) –

    description. Defaults to None.

  • request_body (Optional[dict], default: None ) –

    request body for query with filtering or sorting. Defaults to None. Check https://developers.notion.com/reference/post-database-query for detailed usage of BODY_PARAM.

Returns:

  • _type_

    request response code (200 if succeeded), response text, results (None if request failed)

Source code in ResearchToolkit/notion/database.py
def query_database(
    database_id: str,
    token_path: str = RESEARCH_API_PATH,
    token: Optional[str] = None,
    request_body: Optional[dict] = None,
):
    """
        query a database.
        refer https://developers.notion.com/reference/post-database-query

    Args:
        database_id (str): _description_
        token_path (str, optional): _description_. Defaults to RESEARCH_API_PATH.
        token (Optional[str], optional): _description_. Defaults to None.
        request_body (Optional[dict], optional): request body for query with filtering or sorting. Defaults to None.
            Check https://developers.notion.com/reference/post-database-query for detailed usage of BODY_PARAM.

    Returns:
        _type_: request response code (200 if succeeded), response text, results (None if request failed)
    """

    if not token:
        token = get_token(token_path)

    headers = {
        "Authorization": f"Bearer {token}",
        "Notion-Version": "2022-06-28",
        "accept": "application/json",
        "content-type": "application/json",
    }

    api_url = f"https://api.notion.com/v1/databases/{database_id}/query"

    request_body = {
        "page_size": QUERY_PAGE_SIZE,
        **(request_body or {}),
    }

    results = None
    while True:
        response = requests.post(api_url, headers=headers, json=request_body)
        if response.status_code != RESPONSE_SUCCESS:
            raise RuntimeError(f"Notion Error: {response.text}")

        pages = response.json()["results"]
        if results is None:
            results = pages
        else:
            assert pages[0]["id"] == results[-1]["id"]
            results += pages[1:]

        if len(pages) < QUERY_PAGE_SIZE:
            break

        request_body["start_cursor"] = pages[-1]["id"]

    return response.status_code, response.text, results

get_property_value

get_property_value(property_)
Source code in ResearchToolkit/notion/database.py
def get_property_value(property_):
    property_type = property_["type"]
    property_type = (
        property_type.replace("rich_text", "text")
        .replace("people", "person")
        .replace("phone_number", "phone")
    )
    if property_type == "rollup":
        value = [get_property_value(p) for p in property_["rollup"]["array"]]
    else:
        if property_type in PROPERTIES:
            value = PROPERTIES[property_type].get_value(property_)
        else:
            # if the property type is not in PROPERTIES, results can be less specific.
            value = BasicProperty.get_value(property_)
    return value

get_database_in_pd_dataframe

get_database_in_pd_dataframe(database_id: str, token_path: str = RESEARCH_API_PATH, token: Optional[str] = None, request_body: Optional[dict] = None)

get notion database and return it in pandas dataframe.

Parameters:

  • database_id (str) –

    description

  • token_path (str, default: RESEARCH_API_PATH ) –

    description. Defaults to RESEARCH_API_PATH.

  • token (Optional[str], default: None ) –

    description. Defaults to None.

  • request_body (Optional[dict], default: None ) –

    request body for query with filtering or sorting. Defaults to None. Check https://developers.notion.com/reference/post-database-query for detailed usage of BODY_PARAM.

Returns:

  • pd.DataFrame: description

Source code in ResearchToolkit/notion/database.py
def get_database_in_pd_dataframe(
    database_id: str,
    token_path: str = RESEARCH_API_PATH,
    token: Optional[str] = None,
    request_body: Optional[dict] = None,
):
    """
    get notion database and return it in pandas dataframe.

    Args:
        database_id (str): _description_
        token_path (str, optional): _description_. Defaults to RESEARCH_API_PATH.
        token (Optional[str], optional): _description_. Defaults to None.
        request_body (Optional[dict], optional): request body for query with filtering or sorting. Defaults to None.
            Check https://developers.notion.com/reference/post-database-query for detailed usage of BODY_PARAM.

    Returns:
        pd.DataFrame: _description_
    """
    status, text, results = query_database(database_id, token_path, token, request_body)

    data = {key: [] for key in results[0]["properties"].keys()}
    for result in results:
        properties = result["properties"]
        for key, property_ in properties.items():
            value = get_property_value(property_)
            data[key].append(value)

    return pd.DataFrame(data)

update_page_data

update_page_data(token: str, page_id: str, data: Dict[str, Any])

Database page의 data를 업데이트 합니다.

Source code in ResearchToolkit/notion/database.py
@use_saige_token_as_default
def update_page_data(
    token: str,
    page_id: str,
    data: Dict[str, Any],
):
    """Database page의 data를 업데이트 합니다."""
    database_fields = retrieve_database_fields(database_id=page_id, token=token, is_page=True)
    properties = convert_data_into_property(data=data, fields=database_fields)

    headers = {
        "Authorization": f"Bearer {token}",
        "Notion-Version": "2022-06-28",
        "accept": "application/json",
        "content-type": "application/json",
    }

    api_url = f"https://api.notion.com/v1/pages/{page_id}"
    data = {"properties": properties}

    response = requests.patch(api_url, headers=headers, json=data)
    return response.status_code, response.text

update_database_fields

update_database_fields(token: str, database_id: str, fields: FieldType)

Database fields (properties) 를 업데이트 합니다.

Source code in ResearchToolkit/notion/database.py
@use_saige_token_as_default
def update_database_fields(
    token: str,
    database_id: str,
    fields: FieldType,
):
    """Database fields (properties) 를 업데이트 합니다."""
    headers = {
        "Authorization": f"Bearer {token}",
        "Notion-Version": "2022-06-28",
        "accept": "application/json",
        "content-type": "application/json",
    }

    api_url = f"https://api.notion.com/v1/databases/{database_id}"

    properties = make_database_property_schema(fields=fields)
    data = {"properties": properties}
    response = requests.patch(api_url, headers=headers, json=data)

    return response.status_code, response.text

update_database_fields_safe

update_database_fields_safe(token: str, database_id: str, fields: FieldType)

Database fields (properties) 를 업데이트 합니다. 데이터베이스에 동일한 이름으로 다른 타입의 프로퍼티가 존재하면 에러를 레이즈 합니다.

Source code in ResearchToolkit/notion/database.py
@use_saige_token_as_default
def update_database_fields_safe(
    token: str,
    database_id: str,
    fields: FieldType,
):
    """Database fields (properties) 를 업데이트 합니다. 데이터베이스에 동일한 이름으로 다른 타입의 프로퍼티가 존재하면 에러를 레이즈 합니다."""
    original_fields = retrieve_database_fields(database_id)
    fields_to_update = {}
    for key, value in fields.items():
        if key not in original_fields:
            fields_to_update.update({key: value})
        elif value != original_fields[key]:
            raise ValueError(
                f"Notion database field `{key}` already exists with type `{original_fields[key]}`."
            )
    if fields_to_update:
        status, message = update_database_fields(
            token=token,
            database_id=database_id,
            fields=fields_to_update,
        )
        if status != RESPONSE_SUCCESS:
            raise RuntimeError(f"Notion Error: {message}")