> ## Documentation Index
> Fetch the complete documentation index at: https://docs.beta.b3os.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Notion

The io.b3os/notion pack: 10 actions with call snippets, fixture outputs, connection setup and error codes, generated from version 1.0.0.

`io.b3os/notion` 1.0.0 · `knowledge`, `documents`, `productivity` · MIT

Search, read and write Notion with your own internal integration: find pages and databases, read a page's properties and text, query a database with Notion filters and sorts, create pages, append paragraphs, update properties, archive pages and comment. Uses Notion API version 2022-06-28. The integration only sees pages and databases shared with it (Share, Connections).

Every call's result carries `upstream_status` and `timing`: `validate_ms`, `inject_ms`, `render_ms`, `upstream_ms`, `map_ms` and `total_ms`. `upstream` is the service's time; the others are B3OS's own ([call actions](/actions/call)). The snippets below show no timing values, because a fixture records none.

## Connection

`token`, type `bearer`: Notion integration token.

The internal integration secret (ntn_ or secret_) from notion.so/profile/integrations, or an OAuth access token of your own public integration. Share each page or database the actions need with the integration.

How to get one: [developers.notion.com](https://developers.notion.com/docs/authorization).

The credential is sent only to `api.notion.com`.

Store the credential once as a [vault connection](/vault) for this pack and key, then name its id in a call's `connections`. Leave the key out and B3OS uses the project's newest connection for the pack and key without a `subject` ([connections](/actions/call#connections)).

Hosts it reaches: `api.notion.com`.

## Actions

| Action | Effect | MCP tool | Title |
|---|---|---|---|
| [`search`](/actions/catalog/notion#notion-search) | read | `notion__search` | Search pages and databases |
| [`get-page`](/actions/catalog/notion#notion-get-page) | read | `notion__get-page` | Get page |
| [`get-page-content`](/actions/catalog/notion#notion-get-page-content) | read | `notion__get-page-content` | Get page content |
| [`get-database`](/actions/catalog/notion#notion-get-database) | read | `notion__get-database` | Get database |
| [`query-database`](/actions/catalog/notion#notion-query-database) | read | `notion__query-database` | Query database |
| [`create-page`](/actions/catalog/notion#notion-create-page) | write | `notion__create-page` | Create page |
| [`append-paragraphs`](/actions/catalog/notion#notion-append-paragraphs) | write | `notion__append-paragraphs` | Append paragraphs |
| [`update-page-properties`](/actions/catalog/notion#notion-update-page-properties) | write | `notion__update-page-properties` | Update page properties |
| [`archive-page`](/actions/catalog/notion#notion-archive-page) | write | `notion__archive-page` | Archive page |
| [`add-comment`](/actions/catalog/notion#notion-add-comment) | write | `notion__add-comment` | Comment on page |

search

**Search pages and databases.** Search the pages and databases shared with the integration by title, most recently edited first, optionally only pages or only databases. Returns ids, titles, URLs and edit times; page with next_cursor.

Ref `io.b3os/notion/search@1.0.0` · effect `read` · connection `token` · MCP tool `notion__search`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/search@1",
          "input": {"query": "roadmap", "page_size": 2},
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/search@1",
      input: { query: "roadmap", page_size: 2 },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/search@1",
        "input": {"query": "roadmap", "page_size": 2},
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__search",
        "arguments": {"query": "roadmap", "page_size": 2}
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__search` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Search pages and databases (documented response shape, example values). From the bundle's `fixtures/search.json`, not a live call.

```json
{
  "results": [
    {
      "object": "page",
      "id": "59833787-2cf9-4fdf-8782-e53db20768a5",
      "title": "Q4 roadmap",
      "url": "https://www.notion.so/Q4-roadmap-598337872cf94fdf8782e53db20768a5",
      "created_time": "2026-10-20T15:00:00.000Z",
      "last_edited_time": "2026-10-25T21:30:00.000Z",
      "archived": false,
      "parent_type": "database_id"
    },
    {
      "object": "database",
      "id": "d9824bdc-8445-4327-be8b-5b47500af6ce",
      "title": "Roadmap items",
      "url": "https://www.notion.so/d9824bdc84454327be8b5b47500af6ce",
      "created_time": "2026-09-01T10:00:00.000Z",
      "last_edited_time": "2026-10-25T20:00:00.000Z",
      "archived": false,
      "parent_type": "page_id"
    }
  ],
  "has_more": true,
  "next_cursor": "e6c6f5ff-5e6b-4c5b-9a1e-1c1b0f5e8b7a"
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

get-page

**Get page.** One page's title, URL, parent, edit times and all property values (status, people, dates, relations, ...) in Notion's shape. Its text is in get-page-content.

Ref `io.b3os/notion/get-page@1.0.0` · effect `read` · connection `token` · MCP tool `notion__get-page`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/get-page@1",
          "input": {"page_id": "59833787-2cf9-4fdf-8782-e53db20768a5"},
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/get-page@1",
      input: { page_id: "59833787-2cf9-4fdf-8782-e53db20768a5" },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/get-page@1",
        "input": {"page_id": "59833787-2cf9-4fdf-8782-e53db20768a5"},
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__get-page",
        "arguments": {"page_id": "59833787-2cf9-4fdf-8782-e53db20768a5"}
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__get-page` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Get page (documented response shape, example values). From the bundle's `fixtures/get-page.json`, not a live call.

```json
{
  "object": "page",
  "id": "59833787-2cf9-4fdf-8782-e53db20768a5",
  "title": "Q4 roadmap",
  "url": "https://www.notion.so/Q4-roadmap-598337872cf94fdf8782e53db20768a5",
  "created_time": "2026-10-20T15:00:00.000Z",
  "last_edited_time": "2026-10-25T21:30:00.000Z",
  "archived": false,
  "parent_type": "database_id",
  "properties": {
    "Status": {
      "id": "%3AA%3F",
      "type": "status",
      "status": {"id": "1", "name": "In progress", "color": "blue"}
    },
    "Owner": {"id": "bQk%5D", "type": "people", "people": []},
    "Name": {
      "id": "title",
      "type": "title",
      "title": [
        {
          "type": "text",
          "text": {"content": "Q4 roadmap", "link": null},
          "plain_text": "Q4 roadmap",
          "href": null,
          "annotations": {
            "bold": false,
            "italic": false,
            "strikethrough": false,
            "underline": false,
            "code": false,
            "color": "default"
          }
        }
      ]
    }
  }
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

get-page-content

**Get page content.** The blocks of a page (or of any block with children) in order, each with its type (paragraph, heading_1, to_do, bulleted_list_item, code, ...), plain text and whether it has nested children. One level per call: read a nested block by passing its id; page with next_cursor.

Ref `io.b3os/notion/get-page-content@1.0.0` · effect `read` · connection `token` · MCP tool `notion__get-page-content`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/get-page-content@1",
          "input": {"block_id": "59833787-2cf9-4fdf-8782-e53db20768a5", "page_size": 3},
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/get-page-content@1",
      input: { block_id: "59833787-2cf9-4fdf-8782-e53db20768a5", page_size: 3 },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/get-page-content@1",
        "input": {
            "block_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "page_size": 3,
        },
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__get-page-content",
        "arguments": {
          "block_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
          "page_size": 3
        }
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__get-page-content` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Get page content (documented response shape, example values). From the bundle's `fixtures/get-page-content.json`, not a live call.

```json
{
  "blocks": [
    {
      "id": "c02fc1d3-db8b-45c5-a222-27595b15aea7",
      "type": "heading_2",
      "text": "Goals",
      "has_children": false,
      "checked": null
    },
    {
      "id": "acc7eb06-05cd-4603-a384-5e1e4f1f4e72",
      "type": "to_do",
      "text": "Ship checkout v2",
      "has_children": false,
      "checked": false
    },
    {
      "id": "5e4f3a2b-1c0d-4e9f-8a7b-6c5d4e3f2a1b",
      "type": "child_page",
      "text": "Launch checklist",
      "has_children": true,
      "checked": null
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

get-database

**Get database.** A database's title, URL, the name of its title property and its property schema, keyed by property name: each property's type and, for select, multi_select and status, the allowed options. Read it before query-database or create-page to know the property names.

Ref `io.b3os/notion/get-database@1.0.0` · effect `read` · connection `token` · MCP tool `notion__get-database`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/get-database@1",
          "input": {"database_id": "d9824bdc-8445-4327-be8b-5b47500af6ce"},
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/get-database@1",
      input: { database_id: "d9824bdc-8445-4327-be8b-5b47500af6ce" },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/get-database@1",
        "input": {"database_id": "d9824bdc-8445-4327-be8b-5b47500af6ce"},
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__get-database",
        "arguments": {"database_id": "d9824bdc-8445-4327-be8b-5b47500af6ce"}
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__get-database` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Get database (documented response shape, example values). From the bundle's `fixtures/get-database.json`, not a live call.

```json
{
  "id": "d9824bdc-8445-4327-be8b-5b47500af6ce",
  "title": "Roadmap items",
  "url": "https://www.notion.so/d9824bdc84454327be8b5b47500af6ce",
  "title_property": "Name",
  "properties": {
    "Name": {"id": "title", "name": "Name", "type": "title", "title": {}},
    "Status": {
      "id": "%3AA%3F",
      "name": "Status",
      "type": "status",
      "status": {
        "options": [
          {"id": "1", "name": "Not started", "color": "default"},
          {"id": "2", "name": "In progress", "color": "blue"},
          {"id": "3", "name": "Done", "color": "green"}
        ],
        "groups": []
      }
    },
    "Due": {"id": "M%3BBw", "name": "Due", "type": "date", "date": {}}
  }
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

query-database

**Query database.** Rows (pages) of a database matching a Notion filter, in a Notion sort order: for example filter \{"property": "Status", "status": \{"equals": "In progress"\}\} and sorts [\{"property": "Due", "direction": "ascending"\}]. Returns each row's title, URL and property values; page with next_cursor.

Ref `io.b3os/notion/query-database@1.0.0` · effect `read` · connection `token` · MCP tool `notion__query-database`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/query-database@1",
          "input": {
            "database_id": "d9824bdc-8445-4327-be8b-5b47500af6ce",
            "filter": {"property": "Status", "status": {"equals": "In progress"}},
            "page_size": 1
          },
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/query-database@1",
      input: {
        database_id: "d9824bdc-8445-4327-be8b-5b47500af6ce",
        filter: { property: "Status", status: { equals: "In progress" } },
        page_size: 1,
      },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    });
    console.log(result.output);
    ```
  **Python**

```python
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/query-database@1",
        "input": {
            "database_id": "d9824bdc-8445-4327-be8b-5b47500af6ce",
            "filter": {"property": "Status", "status": {"equals": "In progress"}},
            "page_size": 1,
        },
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    })
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__query-database",
        "arguments": {
          "database_id": "d9824bdc-8445-4327-be8b-5b47500af6ce",
          "filter": {"property": "Status", "status": {"equals": "In progress"}},
          "page_size": 1
        }
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__query-database` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Query database (documented response shape, example values). From the bundle's `fixtures/query-database.json`, not a live call.

```json
{
  "results": [
    {
      "object": "page",
      "id": "59833787-2cf9-4fdf-8782-e53db20768a5",
      "title": "Q4 roadmap",
      "url": "https://www.notion.so/Q4-roadmap-598337872cf94fdf8782e53db20768a5",
      "created_time": "2026-10-20T15:00:00.000Z",
      "last_edited_time": "2026-10-25T21:30:00.000Z",
      "archived": false,
      "parent_type": "database_id",
      "properties": {
        "Status": {
          "id": "%3AA%3F",
          "type": "status",
          "status": {"id": "1", "name": "In progress", "color": "blue"}
        },
        "Owner": {"id": "bQk%5D", "type": "people", "people": []},
        "Name": {
          "id": "title",
          "type": "title",
          "title": [
            {
              "type": "text",
              "text": {"content": "Q4 roadmap", "link": null},
              "plain_text": "Q4 roadmap",
              "href": null,
              "annotations": {
                "bold": false,
                "italic": false,
                "strikethrough": false,
                "underline": false,
                "code": false,
                "color": "default"
              }
            }
          ]
        }
      }
    }
```

The first 40 of 44 lines; the fixture file has the rest.

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

create-page

**Create page.** Create a page with a title and an optional first paragraph, as a child of a page (parent_page_id) or as a row of a database (database_id). For a database row the title goes into the property named by title_property (default Name); to set other columns too, pass properties in Notion's shape including the title property, and title is then ignored. Returns the new page's id and URL. Not idempotent.

Ref `io.b3os/notion/create-page@1.0.0` · effect `write` · connection `token` · MCP tool `notion__create-page`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/create-page@1",
          "input": {
            "parent_page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "title": "Retro notes",
            "content": "What went well: the release train."
          },
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/create-page@1",
      input: {
        parent_page_id: "59833787-2cf9-4fdf-8782-e53db20768a5",
        title: "Retro notes",
        content: "What went well: the release train.",
      },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/create-page@1",
        "input": {
            "parent_page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "title": "Retro notes",
            "content": "What went well: the release train.",
        },
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__create-page",
        "arguments": {
          "parent_page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
          "title": "Retro notes",
          "content": "What went well: the release train."
        }
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__create-page` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Create page (documented response shape, example values). From the bundle's `fixtures/create-page.json`, not a live call.

```json
{
  "id": "7a8b9c0d-1e2f-4a3b-8c4d-5e6f7a8b9c0d",
  "url": "https://www.notion.so/Retro-notes-7a8b9c0d1e2f4a3b8c4d5e6f7a8b9c0d",
  "created_time": "2026-10-20T15:00:00.000Z"
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

append-paragraphs

**Append paragraphs.** Append plain-text paragraphs (each up to 2,000 characters, at most 100) to the end of a page or block. Returns the ids of the new blocks. Not idempotent.

Ref `io.b3os/notion/append-paragraphs@1.0.0` · effect `write` · connection `token` · MCP tool `notion__append-paragraphs`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/append-paragraphs@1",
          "input": {
            "block_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "paragraphs": ["Decision: ship Thursday.", "Owner: Mona."]
          },
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/append-paragraphs@1",
      input: {
        block_id: "59833787-2cf9-4fdf-8782-e53db20768a5",
        paragraphs: ["Decision: ship Thursday.", "Owner: Mona."],
      },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/append-paragraphs@1",
        "input": {
            "block_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "paragraphs": ["Decision: ship Thursday.", "Owner: Mona."],
        },
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__append-paragraphs",
        "arguments": {
          "block_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
          "paragraphs": ["Decision: ship Thursday.", "Owner: Mona."]
        }
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__append-paragraphs` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Append paragraphs (documented response shape, example values). From the bundle's `fixtures/append-paragraphs.json`, not a live call.

```json
{
  "block_ids": [
    "9b8a7c6d-5e4f-4a3b-2c1d-0e9f8a7b6c5d",
    "8a7b6c5d-4e3f-4a2b-1c0d-9e8f7a6b5c4d"
  ]
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

update-page-properties

**Update page properties.** Set property values of a page or database row, in Notion's shape, for example \{"Status": \{"status": \{"name": "Done"\}\}\}. Properties not named keep their values.

Ref `io.b3os/notion/update-page-properties@1.0.0` · effect `write` · connection `token` · MCP tool `notion__update-page-properties`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/update-page-properties@1",
          "input": {
            "page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "properties": {"Status": {"status": {"name": "Done"}}}
          },
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/update-page-properties@1",
      input: {
        page_id: "59833787-2cf9-4fdf-8782-e53db20768a5",
        properties: { Status: { status: { name: "Done" } } },
      },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/update-page-properties@1",
        "input": {
            "page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "properties": {"Status": {"status": {"name": "Done"}}},
        },
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__update-page-properties",
        "arguments": {
          "page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
          "properties": {"Status": {"status": {"name": "Done"}}}
        }
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__update-page-properties` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Update page properties (documented response shape, example values). From the bundle's `fixtures/update-page-properties.json`, not a live call.

```json
{
  "object": "page",
  "id": "59833787-2cf9-4fdf-8782-e53db20768a5",
  "title": "Q4 roadmap",
  "url": "https://www.notion.so/Q4-roadmap-598337872cf94fdf8782e53db20768a5",
  "created_time": "2026-10-20T15:00:00.000Z",
  "last_edited_time": "2026-10-25T21:30:00.000Z",
  "archived": false,
  "parent_type": "database_id",
  "properties": {
    "Status": {
      "id": "%3AA%3F",
      "type": "status",
      "status": {"id": "1", "name": "In progress", "color": "blue"}
    },
    "Owner": {"id": "bQk%5D", "type": "people", "people": []},
    "Name": {
      "id": "title",
      "type": "title",
      "title": [
        {
          "type": "text",
          "text": {"content": "Q4 roadmap", "link": null},
          "plain_text": "Q4 roadmap",
          "href": null,
          "annotations": {
            "bold": false,
            "italic": false,
            "strikethrough": false,
            "underline": false,
            "code": false,
            "color": "default"
          }
        }
      ]
    }
  }
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

archive-page

**Archive page.** Move a page (or database row) to the trash. It can be restored from Notion's trash for 30 days.

Ref `io.b3os/notion/archive-page@1.0.0` · effect `write` · connection `token` · MCP tool `notion__archive-page`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/archive-page@1",
          "input": {"page_id": "59833787-2cf9-4fdf-8782-e53db20768a5"},
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/archive-page@1",
      input: { page_id: "59833787-2cf9-4fdf-8782-e53db20768a5" },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/archive-page@1",
        "input": {"page_id": "59833787-2cf9-4fdf-8782-e53db20768a5"},
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__archive-page",
        "arguments": {"page_id": "59833787-2cf9-4fdf-8782-e53db20768a5"}
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__archive-page` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Archive page (documented response shape, example values). From the bundle's `fixtures/archive-page.json`, not a live call.

```json
{"id": "59833787-2cf9-4fdf-8782-e53db20768a5", "archived": true}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |

add-comment

**Comment on page.** Add a comment to a page's discussion, plain text up to 2,000 characters. The integration needs the Insert comments capability. Not idempotent.

Ref `io.b3os/notion/add-comment@1.0.0` · effect `write` · connection `token` · MCP tool `notion__add-comment`

**curl**

```bash
    curl -s https://beta-api.b3os.org/v1/actions/call \
      -H "Authorization: Bearer $B3OS_API_KEY" \
      -H "Idempotency-Key: 7c1e2f6a-1d43-4a8e-b2a5-3f0c9d5e8b11" \
      -H "Content-Type: application/json" \
      -d '{
          "ref": "io.b3os/notion/add-comment@1",
          "input": {
            "page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "text": "Looks good to me."
          },
          "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"}
        }'
    ```
  **TypeScript**

```ts
    import { B3OS } from "@b3os/sdk";

    const b3os = new B3OS();
    const result = await b3os.actions.call({
      ref: "io.b3os/notion/add-comment@1",
      input: {
        page_id: "59833787-2cf9-4fdf-8782-e53db20768a5",
        text: "Looks good to me.",
      },
      connections: { token: "conn_01m5t6cbgdjs1ketgcqwa2sne8" },
    }, { idempotencyKey: crypto.randomUUID() });
    console.log(result.output);
    ```
  **Python**

```python
    import uuid
    from b3os import B3OS

    b3os = B3OS()
    result = b3os.actions.call({
        "ref": "io.b3os/notion/add-comment@1",
        "input": {
            "page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
            "text": "Looks good to me.",
        },
        "connections": {"token": "conn_01m5t6cbgdjs1ketgcqwa2sne8"},
    }, idempotency_key=str(uuid.uuid4()))
    print(result["output"])
    ```
  **MCP**

```json
    {
      "method": "tools/call",
      "params": {
        "name": "notion__add-comment",
        "arguments": {
          "page_id": "59833787-2cf9-4fdf-8782-e53db20768a5",
          "text": "Looks good to me."
        }
      }
    }
    ```

    Expose the pack as tools with `--packs notion` on the local server or `?packs=notion` on the remote URL, and the agent calls `notion__add-comment` with the action's input. The tool uses your newest connection for each key without a `subject`. Without exposing the pack, `actions_call` takes the same input with `ref`.

Output, labeled `fixture`: Comment on page (documented response shape, example values). From the bundle's `fixtures/add-comment.json`, not a live call.

```json
{
  "id": "3c4d5e6f-7a8b-4c9d-0e1f-2a3b4c5d6e7f",
  "discussion_id": "f1e2d3c4-b5a6-4978-8f6e-5d4c3b2a1f0e",
  "created_time": "2026-10-26T08:00:00.000Z"
}
```

When the service answers with an error, the call fails with [`upstream_error`](/errors#upstream_error) and `pack_error.code` is one of:

| `pack_error.code` | Service status | Retryable | Message |
|---|---|---|---|
| `not_found` | 404 | no | Not found, or the page or database is not shared with the integration (Share, Connections). |
| `connection_unauthorized` | 401 | no | Notion rejected the integration token. |
| `forbidden` | 403 | no | built from the service's response |
| `conflict` | 409 | yes | built from the service's response |
| `rate_limited` | 429 | yes | Notion rate limit reached (about 3 requests a second per integration). |
| `invalid_request` | 400 | no | built from the service's response |