PolderAPI

Docs API

Blocks

Read, append, change and delete the blocks that make up a page.

Base URLhttps://docs.polder.work

The block object

{
  "object": "block",
  "id": "01k8x2n7b4c6d8f0g2h4j6k8lm",
  "parent": { "type": "page_id", "page_id": "01k8x2m4t7q9b3n5v6c8d0f2gh" },
  "created_time": "2026-10-02T09:30:00.000Z",
  "last_edited_time": "2026-10-02T09:30:00.000Z",
  "created_by": { "object": "user", "id": "3" },
  "last_edited_by": { "object": "user", "id": "3" },
  "has_children": false,
  "archived": false,
  "in_trash": false,
  "type": "to_do",
  "to_do": { "rich_text": [ { "plain_text": "Ship it" } ], "checked": false }
}

A page is a block too (child_page), and so is a database (child_database), as in Notion. Their ids work in every block endpoint that reads.

Block types that can be created and changed through the API:

Type Fields in its body
paragraph, heading_1, heading_2, heading_3, heading_4 (Polder only), quote, bulleted_list_item, numbered_list_item, toggle rich_text
to_do rich_text, checked
code rich_text, language
callout rich_text, icon ({"emoji": "💡"} or a string), color
equation expression
bookmark, embed url
image, video, audio, file external.url, caption, name. Only external files: uploads are refused with 400
divider, table_of_contents, breadcrumb none
column_list, column none; they hold children

Other block types (tables, synced blocks, buttons, form embeds…) are returned with their Polder content under their own type name but cannot be created or changed. child_page and child_database are created with POST /pages and POST /databases.

Retrieve a block

GET/api/v1/blocks/{id}capability read_content

Returns the block object. 404 object_not_found when the block does not exist or is not shared with the integration.

curl https://docs.polder.work/api/v1/blocks/01k8x2n7b4c6d8f0g2h4j6k8lm \
  -H "Authorization: Bearer $POLDER_DOCS_KEY"

List block children

GET/api/v1/blocks/{id}/childrencapability read_content

The blocks directly inside a page or block, in order, as a paginated list (?page_size=…&start_cursor=…). has_children on each one tells you whether to fetch deeper. A database has no children here: its rows come from a query.

curl "https://docs.polder.work/api/v1/blocks/01k8x2m4t7q9b3n5v6c8d0f2gh/children?page_size=50" \
  -H "Authorization: Bearer $POLDER_DOCS_KEY"

Append block children

PATCH/api/v1/blocks/{id}/childrencapability insert_content

Adds blocks inside a page or block. Returns a list of the new top-level blocks.

Body

Field Type Required Description
children array yes 1 to 100 blocks, nested ones included, at most two levels of nesting. Each is {"type": "to_do", "to_do": {…}}; type may be left out when the body key names it
after string no Id of a child of this block. The new blocks go after it instead of at the end
  • A database refuses blocks (400): add rows by creating pages with the database as parent.
  • A locked page refuses the request (400). A block that cannot hold children refuses children of its own.
  • A type that cannot be created returns 400 validation_error and lists the types that can.
curl -X PATCH https://docs.polder.work/api/v1/blocks/01k8x2m4t7q9b3n5v6c8d0f2gh/children \
  -H "Authorization: Bearer $POLDER_DOCS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "children": [
      { "type": "bulleted_list_item", "bulleted_list_item": {
          "rich_text": [ { "text": { "content": "Parent" } } ],
          "children": [ { "type": "bulleted_list_item", "bulleted_list_item": { "rich_text": [ { "text": { "content": "Child" } } ] } } ]
      } },
      { "type": "code", "code": { "rich_text": [ { "text": { "content": "echo 1;" } } ], "language": "php" } }
    ]
  }'

Update a block

PATCH/api/v1/blocks/{id}capability update_content

Send the block's own type with the fields to change; fields you leave out stay as they are. Returns the block.

{ "to_do": { "checked": true } }
  • A block's type cannot be changed: sending another type's body returns 400 validation_error.
  • {"child_page": {"title": …}} renames a sub-page. A database is renamed with PATCH /databases/{id}.
  • in_trash (or archived) works as on pages: true moves the block and everything in it to the trash, false restores it. A block in the trash accepts only {"in_trash": false}.
  • A block on a locked page cannot be changed.
curl -X PATCH https://docs.polder.work/api/v1/blocks/01k8x2n7b4c6d8f0g2h4j6k8lm \
  -H "Authorization: Bearer $POLDER_DOCS_KEY" \
  -H "Content-Type: application/json" \
  -d '{"to_do": {"checked": true}}'

Delete a block

DELETE/api/v1/blocks/{id}capability update_content

Moves the block, and everything inside it, to the trash. Returns the block with in_trash: true. Restore it with PATCH and {"in_trash": false}. Needs delete permission on the block, and fails on a locked page.

curl -X DELETE https://docs.polder.work/api/v1/blocks/01k8x2n7b4c6d8f0g2h4j6k8lm \
  -H "Authorization: Bearer $POLDER_DOCS_KEY"