API
Rich text
Rich text fields are ProseMirror-style JSON documents. The nodes and marks, embedded entries and assets, writing it as Markdown, and the HTML the delivery API can render instead.
Rich text fields are ProseMirror-style JSON documents, with TipTap's node and mark names. The entry editor writes exactly this format, and the delivery API answers it by default.
{
"type": "doc",
"content": [
{
"type": "heading",
"attrs": { "level": 2 },
"content": [{ "type": "text", "text": "Intro" }]
},
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Some " },
{ "type": "text", "text": "bold", "marks": [{ "type": "bold" }] }
]
},
{
"type": "embeddedAsset",
"attrs": { "id": "asset_…", "asset": { "url": "…", "alt": "…" } }
}
]
}- Nodes:
paragraph,heading(level),blockquote,bulletList,orderedList(start),listItem,codeBlock(language),horizontalRule,hardBreak,text,embeddedEntry,embeddedAsset. - Marks:
bold,italic,underline,strike,code,link(href,target,title).
Embeds
Embedded entries and assets are stored by id and checked like references. In delivery responses they are resolved into attrs.entry / attrs.asset, following depth; ones that can't be resolved (unpublished, deleted) are left out.
Writing it as Markdown
The agent API and MCP accept Markdown for a rich text field, and store it as a document; prompt editing reads and writes rich text as Markdown too. Embed an asset with  and an entry with .
As HTML
With ?richtext=html the delivery API answers each rich text field as an HTML string instead:
- images as
<figure><img></figure>, other files as links; - embedded entries as
<div data-entry-id="…" data-content-type="…"></div>, for the site to fill; - links only ever have safe URLs (
http(s):,mailto:,tel:,#and paths): others are refused when content is saved.
Rendering it
- React:
<RichText document={…} />from the React SDK, with your own components per node, mark or embed. - Anything else:
richTextToHtml(doc, { renderEntry, renderAsset })andrichTextToPlainText(doc)from the JavaScript SDK.