1. Source Items
Source Wiki (External APIs)
  • Categories
    • List categories (paginated)
      GET
    • Create a category
      POST
    • Get a single category
      GET
    • Update a category
      PATCH
    • Delete a category
      DELETE
  • Spaces
    • List spaces in a category (paginated)
      GET
    • Create a space
      POST
    • Get a single space
      GET
    • Update a space
      PATCH
    • Delete a space
      DELETE
  • Source Items
    • ProseMirror JSON Schema Reference
    • List source items in a space (paginated)
      GET
    • Create a source item
      POST
    • Get a single source item
      GET
    • Update a source item
      PATCH
    • Delete a source item
      DELETE
  • Schemas
    • User
    • SourceDocument
    • Category
    • Space
    • SourceItem
    • PublishedCategory
    • SuccessEnvelope
    • PaginationMeta
    • PaginationLinks
    • ValidationErrorResponse
    • UnauthenticatedResponse
    • NotFoundResponse
    • ConflictResponse
  1. Source Items

ProseMirror JSON Schema Reference

This document describes the valid ProseMirror JSON structure accepted by the json_content field in the Multiplai Source API. The schema is defined by the extensions loaded in EditorProvider.vue.

Top-level structure#

Every document must be a JSON object with type: "doc" and a content array:
{
  "type": "doc",
  "content": [ /* block nodes */ ]
}
content must contain block nodes only (not inline nodes or text directly).

Global attributes#

These attributes can appear on paragraph, heading, and blockquote nodes.
AttributeTypeDescription
textAlign"left" | "center" | "right" | "justify"Text alignment (from TextAlign)
indentnumber (0–10)Text indent level — each level = 40 px text-indent
blockIndentnumber (0–10)Block indent level — each level = 40 px padding-left

Block nodes#

paragraph#

Plain paragraph. Can be empty or contain inline content.
{ "type": "paragraph" }

{
  "type": "paragraph",
  "attrs": { "textAlign": "left", "indent": 0, "blockIndent": 0 },
  "content": [{ "type": "text", "text": "Hello world" }]
}

heading#

attrs.level is required (1–6).
{
  "type": "heading",
  "attrs": { "level": 1, "textAlign": "left" },
  "content": [{ "type": "text", "text": "Section title" }]
}

blockquote#

Contains block content (typically paragraphs).
{
  "type": "blockquote",
  "attrs": { "blockIndent": 0 },
  "content": [
    { "type": "paragraph", "content": [{ "type": "text", "text": "A quote." }] }
  ]
}

bulletList#

Unordered list. Contains listItem nodes.
{
  "type": "bulletList",
  "content": [
    {
      "type": "listItem",
      "content": [
        { "type": "paragraph", "content": [{ "type": "text", "text": "Item one" }] }
      ]
    }
  ]
}

orderedList#

Ordered list. Accepts attrs.start (default 1).
{
  "type": "orderedList",
  "attrs": { "start": 1 },
  "content": [
    {
      "type": "listItem",
      "content": [
        { "type": "paragraph", "content": [{ "type": "text", "text": "First step" }] }
      ]
    }
  ]
}

listItem#

An item inside bulletList or orderedList. Contains block content.
{
  "type": "listItem",
  "content": [
    { "type": "paragraph", "content": [{ "type": "text", "text": "Item" }] }
  ]
}

codeBlock#

Syntax-highlighted code block (powered by lowlight). Set attrs.language to any highlight.js language identifier or omit for plain text.
{
  "type": "codeBlock",
  "attrs": { "language": "javascript" },
  "content": [{ "type": "text", "text": "const x = 1;" }]
}

horizontalRule#

Thematic break. No content, no attrs.
{ "type": "horizontalRule" }

message-banner#

A callout/alert block with a colored background. Contains block content.
AttributeTypeDefaultValues
typestring"info""info", "warning", "success", "error"
colorstring"#F2F2FD"Any CSS hex color
emojistring""Any emoji character
{
  "type": "message-banner",
  "attrs": { "type": "warning", "color": "#FFF7E6", "emoji": "⚠️" },
  "content": [
    { "type": "paragraph", "content": [{ "type": "text", "text": "This is a warning." }] }
  ]
}

iframe#

An embedded iframe (used for web embeds, not videos — use video for video files).
AttributeTypeDefaultNotes
srcstringnullThe embed URL
widthnumber720Width in pixels
heightnumber405Height in pixels
framebordernumber0
allowfullscreenbooleantrue
float"none" | "left" | "right""none"
videobooleanfalseSet true if embedding a video URL
originalUrlstringnullOriginal URL before embed conversion
typestringnullEmbed provider type (e.g. "youtube")
{
  "type": "iframe",
  "attrs": {
    "src": "https://www.youtube.com/embed/dQw4w9WgXcQ",
    "width": 720,
    "height": 405,
    "frameborder": 0,
    "allowfullscreen": true,
    "float": "none",
    "video": true,
    "type": "youtube"
  }
}

video#

An uploaded video file (distinct from iframe).
AttributeTypeDefaultNotes
srcstring""URL of the video file
widthnumber720Width in pixels
heightnumber405Height in pixels
float"none" | "left" | "right""none"
uploadIdnumbernullInternal upload record ID
{
  "type": "video",
  "attrs": {
    "src": "https://cdn.example.com/video.mp4",
    "width": 720,
    "height": 405,
    "float": "none",
    "uploadId": 42
  }
}

Table nodes#

Tables use three nested node types: table → tableRow → tableCell / tableHeader.

table#

{
  "type": "table",
  "content": [
    {
      "type": "tableRow",
      "content": [
        {
          "type": "tableHeader",
          "attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
          "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "Name" }] }]
        },
        {
          "type": "tableHeader",
          "attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
          "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "Role" }] }]
        }
      ]
    },
    {
      "type": "tableRow",
      "content": [
        {
          "type": "tableCell",
          "attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
          "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "Jane" }] }]
        },
        {
          "type": "tableCell",
          "attrs": { "colspan": 1, "rowspan": 1, "colwidth": null },
          "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "Engineer" }] }]
        }
      ]
    }
  ]
}
tableCell / tableHeader attributes:
AttributeTypeDefaultNotes
colspannumber1
rowspannumber1
colwidthnumber[] | nullnullColumn widths in pixels

Inline nodes#

These appear inside block nodes' content arrays, alongside text nodes.

text#

Plain text. Marks are applied as an array on the node.
{ "type": "text", "text": "Hello " }

{
  "type": "text",
  "text": "bold text",
  "marks": [{ "type": "bold" }]
}

hardBreak#

A line break (<br/>). No attrs.
{ "type": "hardBreak" }

resizable-image#

An image (inline by default).
AttributeTypeDefaultNotes
srcstring""Image URL
altstringnullAlt text
titlestringnullTitle
widthnumber300Width in pixels
heightnumber200Height in pixels
float"none" | "left" | "right""none"
hrefstringnullOptional link URL
uploadIdnumbernullInternal upload record ID
{
  "type": "resizable-image",
  "attrs": {
    "src": "https://cdn.example.com/photo.jpg",
    "alt": "A photo",
    "width": 600,
    "height": 400,
    "float": "none",
    "uploadId": 99
  }
}

mention#

A user mention (@user). Renders as a clickable chip.
AttributeTypeNotes
idnumber | stringThe user's ID
labelstringThe user's display name
{
  "type": "mention",
  "attrs": { "id": 7, "label": "Jane Doe" }
}

date#

An inline date picker widget.
AttributeTypeNotes
datestringISO 8601 date string (e.g. "2026-03-16")
{
  "type": "date",
  "attrs": { "date": "2026-03-16" }
}

page#

An internal page link (links to another source item).
AttributeTypeNotes
pageIdstring | numberThe target source item ID
{
  "type": "page",
  "attrs": { "pageId": 42 }
}

status-chip#

An inline status badge.
AttributeTypeDefaultValues
colorstring"info""info", "success", "warning", "error" or a hex color
textstring—The label text displayed in the chip
{
  "type": "status-chip",
  "attrs": { "color": "success", "text": "Approved" }
}

emoji#

An emoji character node (from @tiptap/extension-emoji).
AttributeTypeNotes
namestringThe emoji shortcode name (e.g. "smile")
{
  "type": "emoji",
  "attrs": { "name": "rocket" }
}

Marks#

Marks are applied to text nodes via the marks array.

bold#

{ "type": "bold" }

italic#

{ "type": "italic" }

strike#

Strikethrough.
{ "type": "strike" }

code#

Inline code span.
{ "type": "code" }

underline#

{ "type": "underline" }

link#

AttributeTypeNotes
hrefstringThe URL
targetstring"_blank" for new tab
relstringe.g. "noopener noreferrer nofollow"
classstringCSS class
{
  "type": "link",
  "attrs": {
    "href": "https://example.com",
    "target": "_blank",
    "rel": "noopener noreferrer nofollow",
    "class": null
  }
}

highlight#

Background highlight. Supports multiple colors (multicolor: true).
AttributeTypeDefaultNotes
colorstringnullCSS color value
{ "type": "highlight", "attrs": { "color": "#ffd666" } }

textStyle#

Carries inline style properties set by TextStyleKit (font size, font family, color, line height, letter spacing, etc.). Only include the attributes you are setting.
AttributeTypeNotes
colorstringCSS color
fontSizestringe.g. "16px"
fontFamilystringe.g. "Inter"
lineHeightstringe.g. "1.5"
letterSpacingstringe.g. "0.02em"
{ "type": "textStyle", "attrs": { "color": "#1890ff", "fontSize": "18px" } }

superscript / subscript#

{ "type": "superscript" }
{ "type": "subscript" }

Full document example#

{
  "type": "doc",
  "content": [
    {
      "type": "heading",
      "attrs": { "level": 1, "textAlign": "left" },
      "content": [{ "type": "text", "text": "Getting Started" }]
    },
    {
      "type": "paragraph",
      "attrs": { "textAlign": "left" },
      "content": [
        { "type": "text", "text": "Welcome to the guide. See " },
        {
          "type": "text",
          "text": "our website",
          "marks": [
            {
              "type": "link",
              "attrs": { "href": "https://example.com", "target": "_blank", "rel": "noopener noreferrer nofollow", "class": null }
            }
          ]
        },
        { "type": "text", "text": " for more info." }
      ]
    },
    {
      "type": "bulletList",
      "content": [
        {
          "type": "listItem",
          "content": [
            {
              "type": "paragraph",
              "content": [
                { "type": "text", "text": "First item with " },
                { "type": "text", "text": "bold", "marks": [{ "type": "bold" }] },
                { "type": "text", "text": " text" }
              ]
            }
          ]
        },
        {
          "type": "listItem",
          "content": [
            { "type": "paragraph", "content": [{ "type": "text", "text": "Second item" }] }
          ]
        }
      ]
    },
    {
      "type": "codeBlock",
      "attrs": { "language": "typescript" },
      "content": [{ "type": "text", "text": "const greeting = 'Hello';" }]
    },
    {
      "type": "message-banner",
      "attrs": { "type": "info", "color": "#F2F2FD", "emoji": "ℹ️" },
      "content": [
        { "type": "paragraph", "content": [{ "type": "text", "text": "This is an informational callout." }] }
      ]
    },
    {
      "type": "resizable-image",
      "attrs": { "src": "https://cdn.example.com/logo.png", "alt": "Logo", "width": 300, "height": 100, "float": "none", "uploadId": null }
    },
    { "type": "horizontalRule" },
    {
      "type": "paragraph",
      "content": [
        { "type": "text", "text": "Assigned to " },
        { "type": "mention", "attrs": { "id": 3, "label": "Jane Doe" } },
        { "type": "text", "text": " — due " },
        { "type": "date", "attrs": { "date": "2026-04-01" } }
      ]
    }
  ]
}

Validation rules#

When submitting json_content via the API (content_type: "json" on creation), the backend validates:
1.
The value must be a JSON object (not a string, array, or primitive).
2.
It must have "type": "doc".
3.
It must have a "content" key whose value is an array.
The backend does not perform deep node-level validation — unknown node types are stored but may not render correctly in the editor.

Quick reference — node type summary#

Node typeCategoryContainer for
docRootblock nodes
paragraphBlockinline nodes, text
headingBlockinline nodes, text
blockquoteBlockblock nodes
bulletListBlocklistItem
orderedListBlocklistItem
listItemBlockblock nodes
codeBlockBlocktext
horizontalRuleBlock—
message-bannerBlockblock nodes
iframeBlock—
videoBlock—
tableBlocktableRow
tableRowBlocktableCell, tableHeader
tableCellBlockblock nodes
tableHeaderBlockblock nodes
textInline—
hardBreakInline—
resizable-imageInline—
mentionInline—
dateInline—
pageInline—
status-chipInline—
emojiInline—
Modified at 2026-03-17 23:15:45
Previous
Delete a space
Next
List source items in a space (paginated)
Built with