notion-sdk-py

ramnesMIT活跃维护

Notion API 的 Python 客户端 SDK,同时支持同步和异步调用,用 dataclasses 和 httpx 封装接口,省去手写请求的麻烦。

Notion API client SDK, rewritten in Python! (sync + async)

3.1.0发布于 2026-05-12 08:58 UTC2,197star +1 / 7 天176fork同步于 2026-11-10 17:47 UTC

怎么上手

由 README 提炼,执行前请确认
pip install notion-client
硬件要求按 README 说明

README 未说明,纯 HTTP 客户端库,无 GPU 或特殊硬件要求

下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

Notion 官方 API 的 Python 客户端 SDK,同步异步双支持,写法对齐 JS 参考实现

Notion API 的 Python 客户端 SDK,同时支持同步和异步调用,用 dataclasses 和 httpx 封装接口,省去手写请求的麻烦。

核心能力

  • 提供 Client 与 AsyncClient 两套同步/异步客户端
  • 所有端点参数合并为单个对象,无需区分 path/query/body
  • 内置 429/529/500/503 自动重试与指数退避抖动
  • 抛出 APIResponseError 并用 APIErrorCode 枚举比对错误码
  • 提供 is_full_page 等辅助函数区分完整与部分响应对象

容易踩的坑

包名是 notion-client 而非 notion-sdk-py,导入名是 notion_client;需先在 Notion 后台创建 integration 并拿到 token 才能调用;500/503 仅在 GET、DELETE 等幂等方法上自动重试,写操作需自行处理重试

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本3.1.0
  1. 3.1.0最新正式版2026-05-12 · 2026-05-12 08:58 UTC

    This version adds support for a whole bunch of new endpoints!

    It also brings automatic retries on rate limits and transient server errors (configurable at the ClientOptions level).

    A few new helpers and constants have been added as well: is_full_view, is_http_response_error, DEFAULT_TIMEOUT_MS and MIN_VIEW_COLUMN_WIDTH.

    Thanks to @tsinglinrain for the help.

    What's Changed

    Full Changelog: https://github.com/ramnes/notion-sdk-py/compare/3.0.0...3.1.0

  2. 3.0.02026-02-16 · 2026-02-16 11:23 UTC
    查看更新说明

    Thanks to all the contributors for this new major version!

    ⚠️ Beware of the following breaking changes:

    • is_full_page_or_database has been removed. Use is_full_page_or_data_source instead.
    • is_api_error_code has been made private.

    What's Changed

    New Contributors

    Full Changelog: https://github.com/ramnes/notion-sdk-py/compare/2.7.0...3.0.0

  3. 2.7.02025-10-31 · 2025-10-31 12:11 UTC
    查看更新说明

    What's Changed

    New Contributors

    Full Changelog: https://github.com/ramnes/notion-sdk-py/compare/2.6.0...2.7.0

  4. 2.6.02025-10-23 · 2025-10-23 14:50 UTC
    查看更新说明

    ⚠️ Beware, Notion-Version has been upgraded to 2025-09-03. This version of the SDK is not compatible with older versions of the API. See Notion's upgrade guide to learn more.

    What's Changed

    New Contributors

    Full Changelog: https://github.com/ramnes/notion-sdk-py/compare/2.5.0...2.6.0

  5. 2.5.02025-08-26 · 2025-08-26 10:35 UTC
    查看更新说明

    What's Changed

    New Contributors

    Full Changelog: https://github.com/ramnes/notion-sdk-py/compare/2.4.0...2.5.0

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    notion-sdk-py

    notion-sdk-py is a simple and easy to use client library for the official Notion API.

    It is meant to be a Python version of the reference JavaScript SDK, so usage should be very similar between both. 😊 (If not, please open an issue or PR!)

    Installation

    pip install notion-client
    

    Usage

    Use Notion's Getting Started Guide to get set up to use Notion's API.

    Import and initialize a client using an integration token or an OAuth access token.

    import os
    from notion_client import Client
    
    notion = Client(auth=os.environ["NOTION_TOKEN"])
    

    In an asyncio environment, use the asynchronous client instead:

    from notion_client import AsyncClient
    
    notion = AsyncClient(auth=os.environ["NOTION_TOKEN"])
    

    Make a request to any Notion API endpoint.

    from pprint import pprint
    
    list_users_response = notion.users.list()
    pprint(list_users_response)
    

    [!NOTE] See the complete list of endpoints in the API reference.

    or with the asynchronous client:

    list_users_response = await notion.users.list()
    pprint(list_users_response)
    

    This would output something like:

    {'results': [{'avatar_url': 'https://secure.notion-static.com/e6a352a8-8381-44d0-a1dc-9ed80e62b53d.jpg',
                  'id': 'd40e767c-d7af-4b18-a86d-55c61f1e39a4',
                  'name': 'Avocado Lovelace',
                  'object': 'user',
                  'person': {'email': '[email protected]'},
                  'type': 'person'},
                 ...]}
    

    All API endpoints are available in both the synchronous and asynchronous clients.

    Endpoint parameters are grouped into a single object. You don't need to remember which parameters go in the path, query, or body.

    my_page = notion.data_sources.query(
        **{
            "data_source_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
            "filter": {
                "property": "Landmark",
                "rich_text": {
                    "contains": "Bridge",
                },
            },
        }
    )
    

    Handling errors

    If the API returns an unsuccessful response, an APIResponseError will be raised.

    The error contains properties from the response, and the most helpful is code. You can compare code to the values in the APIErrorCode object to avoid misspelling error codes.

    import logging
    from notion_client import APIErrorCode, APIResponseError, Client
    
    try:
        notion = Client(auth=os.environ["NOTION_TOKEN"])
        my_page = notion.data_sources.query(
            **{
                "data_source_id": "897e5a76-ae52-4b48-9fdf-e71f5945d1af",
                "filter": {
                    "property": "Landmark",
                    "rich_text": {
                        "contains": "Bridge",
                    },
                },
            }
        )
    except APIResponseError as error:
        if error.code == APIErrorCode.ObjectNotFound:
            #
            # For example: handle by asking the user to select a different data source
            #
            ...
        else:
            # Other error handling code
            print(error)
    

    Logging

    The client emits useful information to a logger. By default, it only emits warnings and errors.

    If you're debugging an application, and would like the client to log request & response bodies, set the log_level option to logging.DEBUG.

    import logging
    from notion_client import Client
    
    notion = Client(
        auth=os.environ["NOTION_TOKEN"],
        log_level=logging.DEBUG,
    )
    

    You may also set a custom logger to emit logs to a destination other than stdout. Have a look at Python's logging cookbook if you want to create your own logger.

    Client options

    Client and AsyncClient both support the following options on initialization. These options are all keys in the single constructor parameter.

    OptionDefault valueTypeDescription
    authNonestringBearer token for authentication. If left undefined, the auth parameter should be set on each request.
    log_levellogging.WARNINGintVerbosity of logs the instance will produce. By default, logs are written to stdout.
    timeout_msDEFAULT_TIMEOUT_MSintNumber of milliseconds to wait before emitting a RequestTimeoutError
    base_urlDEFAULT_BASE_URLstringThe root URL for sending API requests. This can be changed to test with a mock server.
    loggerLog to consolelogging.LoggerA custom logger.
    retrySee constantsRetryOptionsConfiguration for automatic retries on rate limits (429), service overloads (529), and server errors (500, 503). See Automatic retries below.

    Automatic retries

    The client automatically retries requests that fail due to rate limiting or transient server errors. By default, it will retry up to 2 times using exponential back-off with jitter.

    Retryable errors:

    • rate_limited (HTTP 429) - Too many requests; retried for all HTTP methods
    • service_overload (HTTP 529) - Service overloaded; retried for all HTTP methods
    • internal_server_error (HTTP 500) - Server error; retried only for GET and DELETE
    • service_unavailable (HTTP 503) - Service temporarily unavailable; retried only for GET and DELETE

    Server errors (500, 503) are only retried for idempotent HTTP methods (GET, DELETE) to avoid duplicate side effects. Rate limits (429) and service overloads (529) are retried for all methods since the server explicitly asks clients to retry.

    Configuration:

    from notion_client import Client, RetryOptions
    
    notion = Client(
        auth="secret_...",
        retry=RetryOptions(
            max_retries=5,          # Maximum retry attempts (default: 2)
            initial_retry_delay_ms=500,  # Initial delay in ms (default: 1000)
            max_retry_delay_ms=60000,    # Maximum delay in ms (default: 60000)
        ),
    )
    

    To disable automatic retries:

    notion = Client(auth="secret_...", retry=False)
    

    Constants

    The SDK exports named constants for all default values used by the client, as well as useful Notion-specific values. You can import them directly:

    from notion_client import (
        DEFAULT_BASE_URL,          # "https://api.notion.com"
        DEFAULT_TIMEOUT_MS,        # 60_000
        DEFAULT_MAX_RETRIES,       # 2
        DEFAULT_INITIAL_RETRY_DELAY_MS,  # 1_000
        DEFAULT_MAX_RETRY_DELAY_MS,      # 60_000
        MIN_VIEW_COLUMN_WIDTH,     # 32
    )
    

    MIN_VIEW_COLUMN_WIDTH is the minimum width (in pixels) that a table column can have in the Notion UI. Set a property's width to this value when creating or updating a view to make a column appear collapsed -- useful for checkbox or status-as-checkbox columns:

    await notion.views.create(
        database_id=database_id,
        name="My view",
        type="table",
        configuration={
            "table": {
                "properties": [
                    {
                        "property_id": checkbox_prop_id,
                        "visible": True,
                        "width": MIN_VIEW_COLUMN_WIDTH,
                    },
                ],
            },
        },
    )
    

    Full API responses

    The following functions can distinguish between full and partial API responses.

    FunctionPurpose
    is_full_pageDetermine whether an object is a full Page object
    is_full_blockDetermine whether an object is a full Block object
    is_full_data_sourceDetermine whether an object is a full Data source object
    is_full_page_or_data_sourceDetermine whether an object is a full Page object or Data source object
    is_full_userDetermine whether an object is a full User object
    is_full_commentDetermine whether an object is a full Comment object
    from notion_client.helpers import is_full_page
    
    full_or_partial_pages = notion.data_sources.query(
        data_source_id="897e5a76-ae52-4b48-9fdf-e71f5945d1af"
    )
    
    for page in full_or_partial_pages["results"]:
        if not is_full_page_or_data_source(page):
            continue
        print(f"Created at: {page['created_time']}")
    

    Utility functions

    This package also exports a few utility functions that are helpful for dealing with any of the paginated APIs.

    iterate_paginated_api(function, **kwargs)

    This utility turns any paginated API into a generator.

    Parameters:

    • function: Any function on the Notion client that represents a paginated API (i.e. accepts start_cursor.) Example: notion.blocks.children.list.
    • **kwargs: Arguments that should be passed to the API on the first and subsequent calls to the API, for example a block_id.

    Returns:

    A generator over results from the API.

    Example:

    from notion_client.helpers import iterate_paginated_api
    
    for block in iterate_paginated_api(
        notion.blocks.children.list, block_id=parent_block_id
    ):
        # Do something with block.
        ...
    
    collect_paginated_api(function, **kwargs)

    This utility accepts the same arguments as iterate_paginated_api, but collects the results into an in-memory array.

    Before using this utility, check that the data you are dealing with is small enough to fit in memory.

    Parameters:

    • function: Any function on the Notion client that represents a paginated API (i.e. accepts start_cursor.) Example: notion.blocks.children.list.
    • **kwargs: Arguments that should be passed to the API on the first and subsequent calls to the API, for example a block_id.

    Returns:

    An array with results from the API.

    Example:

    from notion_client.helpers import collect_paginated_api
    
    blocks = collect_paginated_api(
        notion.blocks.children.list, block_id=parent_block_id
    )
    # Do something with blocks.
    

    Both utilities also have async versions: async_iterate_paginated_api and async_collect_paginated_api.

    Custom requests

    To make requests directly to a Notion API endpoint instead of using the pre-built families of methods, call the request() method. For example:

    import json
    
    # POST /v1/comments
    response = notion.request(
        path="comments",
        method="post",
        body={
            "parent": {"page_id": "5c6a28216bb14a7eb6e1c50111515c3d"},
            "rich_text": [{"text": {"content": "Hello, world!"}}],
        },
        # No `query` params in this example, only `body`.
    )
    
    print(json.dumps(response, indent=2))
    

    [!TIP] Usually, making custom requests with notion.request() isn't necessary, but can be helpful in some cases, e.g. when upgrading your Notion API version incrementally before upgrading your SDK version. For example, if there's a new or renamed endpoint in the new API version that isn't yet available to call via a dedicated method on Client.

    In the above example, the simpler approach is to use notion.comments.create().

    Another customization you can make is to pass your own httpx.Client or httpx.AsyncClient to the Client or AsyncClient constructor. This might be helpful for some execution environments where the default HTTPX client isn't suitable.

    Verifying webhook signatures

    If your integration receives Notion webhook deliveries, use verify_webhook_signature to confirm each request was sent by Notion and was not tampered with in transit. Notion signs every delivery with HMAC-SHA256 over the raw request body using the subscription's verification token, and places the result in the X-Notion-Signature header as sha256=<hex>.

    import json
    import os
    
    from fastapi import FastAPI, HTTPException, Request
    from notion_client import verify_webhook_signature
    
    app = FastAPI()
    
    
    # The body must be read as the raw bytes that arrived over the wire —
    # JSON-parsed and re-serialized bodies will not verify, because
    # re-serialization changes whitespace and key order.
    @app.post("/notion-webhook")
    async def notion_webhook(request: Request):
        body = await request.body()
        if not verify_webhook_signature(
            body=body,
            signature=request.headers.get("X-Notion-Signature"),
            verification_token=os.environ["NOTION_WEBHOOK_VERIFICATION_TOKEN"],
        ):
            raise HTTPException(status_code=401, detail="invalid signature")
    
        event = json.loads(body)
        # ...handle the event
        return "ok"
    

    The same helper handles the initial verification handshake that Notion sends when you first register a webhook URL — the handshake body ({"verification_token": "..."}) is signed with the same token, so a single code path covers both cases.

    sign_webhook_payload(body, verification_token) produces the same sha256=<hex> header value, which is useful for unit-testing your webhook handler without standing up a real subscription.

    Testing

    Run the tests with the pytest command. If you want to test against all Python versions, you can run tox instead.

    The tests are using pytest-vcr's cassettes for simulating requests to the Notion API. To create new tests or run them without cassettes, you need to set up the environment variables NOTION_TOKEN and NOTION_TEST_PAGE_ID (a page where your integration has all the capabilities enabled).

    The code will use the page at NOTION_TEST_PAGE_ID to generate a temporary environment with the Notion objects to be tested, which will be deleted at the end of the session.

    Requirements and compatibility

    This package supports the following minimum versions:

    • Runtime: Python >= 3.8
    • httpx >= 0.23.0

    Earlier versions may still work, but we encourage people building new applications to upgrade to the current stable.

    Getting help

    If you want to submit a feature request for Notion's API, or are experiencing any issues with the API platform, please email [email protected].

    If you found a bug with the library, please submit an issue.