> ## Documentation Index
> Fetch the complete documentation index at: https://developers.bottari.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Block values

> The block types you can write, the fields each one takes, and how Bottari stores them.

Send a block as an object with one key, the block type. `type` is optional and must match that key, and `object: "block"` is accepted. Other keys from a block you read, such as `id` and `parent`, return 400, so send only the type key and its value.

```json theme={null}
{
  "paragraph": {
    "rich_text": [{ "text": { "content": "Hello" } }],
    "color": "blue_background",
    "children": [
      { "to_do": { "rich_text": [{ "text": { "content": "Nested task" } }], "checked": false } }
    ]
  }
}
```

`rich_text` uses the same items as properties. See [Rich text items](https://developers.bottari.ai/api-reference/property-values.md#rich-text-items).

A value you read can usually be sent back as it is, with these exceptions:

* A `paragraph` you read has `icon: null`, which returns 400. Leave `icon` out.
* A `table`, `column_list`, or `tab` you read has no `children`, which they need. Read the children and add them.
* An `image` you read has `type`, which returns 400 when updating. Leave it out.

## Block types

| `type` | Fields | Required |
| - | - | - |
| `paragraph` | `rich_text`, `color`, `children` | `rich_text` |
| `heading_1`, `heading_2`, `heading_3`, `heading_4` | `rich_text`, `color`, `is_toggleable`, `children` | `rich_text` |
| `bulleted_list_item`, `numbered_list_item`, `quote`, `toggle` | `rich_text`, `color`, `children` | `rich_text` |
| `to_do` | `rich_text`, `color`, `checked`, `children` | `rich_text` |
| `callout` | `rich_text`, `color`, `icon`, `children` | `rich_text` |
| `code` | `rich_text`, `language`, `caption` | `rich_text`, `language` |
| `equation` | `expression` | `expression` |
| `divider`, `breadcrumb` | None. Send `{}`. | |
| `table_of_contents` | `color` | |
| `bookmark`, `embed` | `url`, `caption` | `url` |
| `image`, `video`, `audio`, `pdf` | `external.url`, `caption` | `external.url` |
| `file` | `external.url`, `name`, `caption` | `external.url` |
| `link_to_page` | `page_id` or `database_id` | One of them |
| `table` | `table_width`, `has_column_header`, `has_row_header`, `children` | `table_width`, `children` |
| `table_row` | `cells`, an array of `rich_text` arrays | `cells` |
| `column_list` | `children`, 2 to 5 `column` blocks | `children` |
| `column` | `children`, `width_ratio` | `children` |
| `tab` | `children`, one `paragraph` for each tab | `children` |
| `synced_block` | `synced_from`, `children` | `synced_from` |

These types can't be written: `child_page`, `child_database`, and `unsupported`. To add a subpage, use [Create a page](https://developers.bottari.ai/api-reference/pages/create.md) with `parent.page_id`. Inline databases can't be created through the API.

File uploads aren't available, so `file_upload` values return 404.

## Levels

A request can hold 3 levels of blocks, counting the top level. A `column_list` and its `column` blocks count as one level. To go deeper, append to the third-level block in a later request.

A `column_list` can only be at the top level of a request, and a `table` can't be at the third level. To put one deeper, append it to that block in a later request.

Limits on item counts and size are in [Values and request size](https://developers.bottari.ai/limits/values.md#page-content).

## Colors

`color` accepts `default`, `gray`, `brown`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `red`, and the same colors with `_background`, such as `blue_background`.

| You send | What you read back |
| - | - |
| A background color | The block's `color` has that value. |
| A text color | The block's `color` is `default`, and each text item's `annotations.color` has the value. Sending `default` later doesn't clear it. To clear it, write the text again with `annotations.color`. |
| A `callout` color | One of five tones: `gray_background`, `green_background`, `purple_background`, `orange_background`, `red_background`. Without a color, `gray_background`. |
| `table_of_contents.color` | Ignored. It reads as `gray`. |

## Icons

`callout.icon` accepts `emoji`, `custom_emoji` (from this team), and `icon` (name and color). `null` and `external` return 400. Without an icon, a callout uses 💡.

## Links and files

| Block | Rule |
| - | - |
| `bookmark`, `embed` | `url` must be http(s). `caption` isn't returned when you read the block. |
| `image` | `external.url` must be http(s). Loopback and private IP addresses return 400. |
| `video` | Reads back as `embed`. `caption` isn't returned. |
| `audio`, `file`, `pdf` | Reads back as `bookmark`. `caption` and `name` aren't returned. |
| Links in `rich_text` | A URL with no scheme gets `https://`. `http`, `https`, `mailto`, and `tel` are accepted. A relative URL other than a document address returns 400 `Invalid URL for link.` |

## What Bottari changes when saving

| You send | What's saved |
| - | - |
| Adjacent text items with the same formatting | One item. Empty items are removed. |
| NUL characters and unpaired surrogates in any string | Removed. |
| Formatting on `code` text, mentions, dates, or equations | Plain text and values. The formatting isn't saved. |
| A date mention with a time or end date | The start date only. |
| A paragraph holding only a page mention or a link to one page | The same text plus a trailing space, so it stays text instead of becoming a page card. |
| `link_to_page` with `database_id` | A `paragraph` with a database mention. |
| `code` with `language: "shell"` | Reads back as `bash`. |
| `width_ratio` | A ratio relative to the other columns, so the value you read can differ. It must be under 1. |
| A heading with `children` | A toggle heading, with `is_toggleable: true`. |

## Language values

`language` must be one of these values.

`abap`, `abc`, `agda`, `arduino`, `ascii art`, `assembly`, `bash`, `basic`, `bnf`, `c`, `c#`, `c++`, `clojure`, `coffeescript`, `coq`, `css`, `dart`, `dhall`, `diff`, `docker`, `ebnf`, `elixir`, `elm`, `erlang`, `f#`, `flow`, `fortran`, `gherkin`, `glsl`, `go`, `graphql`, `groovy`, `haskell`, `hcl`, `html`, `idris`, `java`, `javascript`, `json`, `julia`, `kotlin`, `latex`, `less`, `lisp`, `livescript`, `llvm ir`, `lua`, `makefile`, `markdown`, `markup`, `matlab`, `mathematica`, `mermaid`, `nix`, `objective-c`, `ocaml`, `pascal`, `perl`, `php`, `plain text`, `powershell`, `prolog`, `protobuf`, `purescript`, `python`, `r`, `racket`, `reason`, `ruby`, `rust`, `sass`, `scala`, `scheme`, `scss`, `shell`, `smalltalk`, `solidity`, `sql`, `swift`, `toml`, `typescript`, `vb.net`, `verilog`, `vhdl`, `visual basic`, `webassembly`, `xml`, `yaml`, `java/c/c++/c#`

## Tables

`table_width` is the number of cells in each row, and every row must have that many. It can't be changed later. To add a row, append `table_row` blocks to the table.

## Columns

A `column_list` needs at least 2 columns and holds at most 5. If deleting a column leaves one, the list is removed and its blocks move up to the list's place.

## Tabs

Each `paragraph` under a `tab` is one tab. Its text is the tab's name, its `icon` is the tab's icon, and its `children` are the tab's content. Only these paragraphs can have an `icon`. Elsewhere it returns 400 `Cannot set icon on a paragraph block that is not a direct child of a tab block.`

## Synced blocks

| `synced_from` | Result |
| - | - |
| `null` | A new original. `children` becomes its content. |
| `{ "block_id": "<original id>" }` | A copy of that original, showing the same content. `children` is ignored. |

Blocks you append to a copy's ID go into the original. An original can't hold another synced block, and the response is 400. A copy needs an original the integration can read.

## Errors

Validation messages come in three forms.

| Message | Meaning |
| - | - |
| ``body failed validation: body.children[0].paragraph.rich_text should be defined, instead was `undefined`.`` | One value at this path is wrong. |
| `body failed validation. Fix one:` followed by lines | The block didn't match any type. Each line is one type's first problem. |
| `Content creation Failed. Fix the following:` followed by lines | The values have the right shape, but their meaning is wrong, such as an invalid URL or a person who can't be found. Every problem is listed. |

If any block is rejected, nothing in the request is saved.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.