Block types
Every block that can appear in a post or page body — JSON shape, constraints, rendering notes.
A post or page bodyJson is an array of typed blocks. Each block is an object with a discriminator field type plus type-specific fields. v1 ships 13 block types, listed below in alphabetical order.
The same vocabulary is used for the derived structuredBlocks array a post carries when its schemaType has a non-trivial structuredData payload — the recipe card, how-to steps, etc. project into the same blocks, so the consumer renders them with the same renderer it uses for the body.
Per-body cap: 1,000 blocks per post or page.
Stored vs. response shape
The Image block has two shapes:
| Where | Shape |
|---|---|
| When you POST / PATCH a body | { type: 'image', mediaId, alt?, caption? } — no url. |
| When you read a body | { type: 'image', mediaId, alt?, caption?, url: string | null } — Clog joins the referenced media row and inlines the resolved public URL. |
Every other block variant is identical in both shapes.
url can be null if the underlying media row was deleted after the block was saved — render a fallback rather than emitting a broken <img>. See Posts → Image blocks and edits for why this happens.
Inline Markdown
The text-bearing fields on prose blocks (paragraph.text, heading.text, quote.text, quote.attribution, list.items[], callout.body, callout.title) carry raw Markdown source. Only inline marks are in scope — **bold**, _italic_, `code`, [link](url). Block-level Markdown (headings, lists, code blocks) is each its own block type, so you only need an inline parser. See API → Rendering content for the rendering recipe.
The 13 block types
callout
A highlighted note. One of four variants.
{
"type": "callout",
"variant": "info",
"title": "Optional title (inline Markdown)",
"body": "Body text (inline Markdown)."
}| Field | Type | Notes |
|---|---|---|
variant | 'info' | 'warning' | 'success' | 'error' | Required. Drives icon and tint on the rendered output. |
title | string? | Optional bold lead line. Inline Markdown. |
body | string | Required. Inline Markdown. |
code
A code block with a language hint.
{
"type": "code",
"language": "ts",
"code": "console.log('hello');"
}| Field | Type | Notes |
|---|---|---|
language | string | A shortname / extension (ts, tsx, bash, json, python, ...). The consumer passes it to its syntax highlighter. |
code | string | Raw code. Render in a <pre><code> block. |
cta
A call-to-action card with a title, body, and a single link.
{
"type": "cta",
"title": "Read the full guide",
"body": "A short pitch for what's on the other side of the link.",
"linkUrl": "https://example.com/guide",
"linkLabel": "Read the guide →",
"variant": "default"
}| Field | Type | Notes |
|---|---|---|
title | string | Required. The card's main heading. |
body | string | Required. Short description. Inline Markdown is fine. |
linkUrl | string | Required. Absolute or relative URL. |
linkLabel | string | Required. The button / link label. |
variant | 'default' | 'outlined' | Required. Two visual treatments. |
divider
A visual section break (a horizontal rule on most sites).
{ "type": "divider" }No fields beyond type.
faq
An accordion of question / answer pairs. When present in a post body, drives FAQPage JSON-LD on the consumer side.
{
"type": "faq",
"items": [
{ "question": "What is X?", "answer": "X is …" },
{ "question": "How do I Y?", "answer": "You Y by …" }
]
}| Field | Type | Notes |
|---|---|---|
items | { question, answer }[] | 1–50 items. Both fields required per item. |
heading
A subheading. H2, H3, or H4 only (the page title is the H1).
{
"type": "heading",
"level": 2,
"text": "On naming things",
"id": "on-naming-things"
}| Field | Type | Notes |
|---|---|---|
level | 2 | 3 | 4 | Required. |
text | string | Required. Inline Markdown supported. |
id | string? | Optional anchor id. Auto-derived from text (kebab-case) when omitted. Duplicate slugs across heading blocks in the same body are disambiguated with a numeric suffix. |
Heading blocks feed the post's derived tocItems — see Rendering content → derived helpers.
image
An image from the workspace's media library.
{
"type": "image",
"mediaId": "0a4b3c2d-1234-4567-89ab-cdef01234567",
"alt": "A photo of …",
"caption": "Caption shown below the image.",
"url": "https://storage.example.com/.../image.png"
}| Field | Type | Notes |
|---|---|---|
mediaId | string (UUID) | Required. Must reference a media row in the same workspace; cross-workspace references are rejected. |
alt | string? | Optional. Falls back to the media row's alt field when not set per-block. |
caption | string? | Optional. Falls back to the media row's caption. |
url | string | null | Response-only. Resolved public URL — see Stored vs. response shape above. |
Editor-side: cropping or resizing an image in the post editor creates a new media row and repoints the block; the original is untouched. See Posts → Image blocks and edits.
key_takeaways
A short bullet list, typically shown at the top of a post as a TL;DR.
{
"type": "key_takeaways",
"items": [
"First takeaway.",
"Second takeaway.",
"Third."
]
}| Field | Type | Notes |
|---|---|---|
items | string[] | 1–10 items. Each is plain text (no inline Markdown). |
list
An unordered or ordered list.
{
"type": "list",
"style": "bullet",
"items": [
"First item.",
"Second item with **bold**.",
"Third item."
]
}| Field | Type | Notes |
|---|---|---|
style | 'bullet' | 'ordered' | Required. |
items | string[] | Required. Each item supports inline Markdown. |
paragraph
Default prose. The most common block in any post.
{
"type": "paragraph",
"text": "A paragraph of prose with **inline marks** and [links](https://example.com)."
}| Field | Type | Notes |
|---|---|---|
text | string | Required. Up to 10,000 characters. Inline Markdown supported. |
quote
A block quote with an optional attribution line.
{
"type": "quote",
"text": "The quote itself, with **inline marks** if you want them.",
"attribution": "Author Name, Source"
}| Field | Type | Notes |
|---|---|---|
text | string | Required. Inline Markdown supported. |
attribution | string? | Optional. Rendered below the quote (typically as a <cite>). |
tweet_embed
A Tweet / X embed. The consumer typically stamps the X embed script and renders a <blockquote class="twitter-tweet">.
{
"type": "tweet_embed",
"url": "https://twitter.com/anthropicai/status/1234567890"
}| Field | Type | Notes |
|---|---|---|
url | string | Required. The full tweet URL. |
video_embed
A YouTube, Vimeo, or generic video URL. The consumer renders an <iframe> or wraps a player of choice. When present in a post body with schemaType = VideoObject, drives VideoObject JSON-LD.
{
"type": "video_embed",
"url": "https://www.youtube.com/embed/dQw4w9WgXcQ",
"title": "Optional title shown over the player"
}| Field | Type | Notes |
|---|---|---|
url | string | Required. Embed URL (YouTube's /embed/<id>, Vimeo's /video/<id>, etc.). |
title | string? | Optional. Useful for accessibility / iframe title. |
Derived helpers (on the post response)
Three fields the backend derives from bodyJson on every save and ships on the read response. None of them are blocks — they're flat fields you read directly:
| Field | Shape | Use for |
|---|---|---|
bodyText | string | Plain-text projection of the body (whitespace-joined block text). Excerpts, search indexing, character counts. |
tocItems | { level: 2|3|4, text, id }[] | A sidebar table of contents. Walks heading blocks in document order. |
readingTimeMin | number | ceil(wordCount / 230), minimum 1. Pages don't carry this — only posts. |
Related
- API → Rendering content — how to render each block on a consumer site.
- API → SEO and JSON-LD — the
structuredBlocksreuse pattern. - Posts → Body (the block editor) — what an editor sees in the dashboard.