Content JSON Schema Reference
This document describes the required JSON schema for importing content into the Content Editor.
Field Specifications
Metadata Fields
| Field | Type | Required | Description |
|---|---|---|---|
title | string | Yes | The main title of the content (max 255 chars recommended) |
slug | string | Yes | URL-friendly identifier (lowercase, hyphens, no spaces) |
subtitle | string | No | Optional subtitle or tagline |
excerpt | string | No | Brief description for previews (150-200 chars recommended) |
meta_title | string | No | SEO title (max 60 characters) |
meta_description | string | No | SEO description (max 160 characters) |
Classification Fields
| Field | Type | Required | Allowed Values |
|---|---|---|---|
content_type | string | No | blog, tutorial, lesson, tip, case_study |
access_level | string | No | public, registered, premium, course_specific |
difficulty_level | string | No | beginner, intermediate, advanced |
tags | array | No | Array of strings (e.g., ["ai", "automation"]) |
Media Fields
| Field | Type | Required | Description |
|---|---|---|---|
featured_image | string | No | Full URL to image (must be valid URL format) |
video_url | string | No | YouTube or Vimeo URL (must be valid URL format) |
Content Field (TipTap JSON)
The content field uses TipTap/ProseMirror JSON format:
{
"content": {
"type": "doc",
"content": [ /* array of nodes */ ]
}
}
Quick Reference Schema
{
"title": "string (required)",
"slug": "string (required, URL-friendly)",
"subtitle": "string (optional)",
"excerpt": "string (optional)",
"content_type": "blog | tutorial | lesson | tip | case_study",
"access_level": "public | registered | premium | course_specific",
"difficulty_level": "beginner | intermediate | advanced",
"tags": ["array", "of", "strings"],
"featured_image": "string (optional, must be valid URL)",
"video_url": "string (optional, must be valid URL)",
"meta_title": "string (optional, max 60 chars)",
"meta_description": "string (optional, max 160 chars)",
"content": {
"type": "doc",
"content": [
{
"type": "heading | paragraph | bulletList | orderedList | blockquote | codeBlock | image | imageGallery | videoEmbed | youtube | mermaidDiagram | table",
"attrs": { }, // varies by node type (see detailed sections below)
"content": [...]
}
]
}
}
New Content Types Added:
imageGallery- Multiple images with captions and alt textvideoEmbed- Embed YouTube, Vimeo, or direct video files with captionsmermaidDiagram- Interactive diagrams (flowcharts, sequence diagrams, etc.)- Enhanced
codeBlock- Now includes language selector and copy button
TipTap Node Types
Important: Use camelCase!
TipTap requires camelCase for all node type names:
- ✅
bulletList(correct) - ❌
bullet_list(wrong) - ✅
orderedList(correct) - ❌
ordered_list(wrong) - ✅
listItem(correct) - ❌
list_item(wrong) - ✅
codeBlock(correct) - ❌
code_block(wrong)
Supported Node Types
- Basic Content: heading, paragraph, bulletList, orderedList, listItem, blockquote
- Code: codeBlock (enhanced with language selector and copy button)
- Media: image, imageGallery, videoEmbed, youtube
- Advanced: table, mermaidDiagram
- Formatting: bold, italic, code, link, strike
1. Heading
{
"type": "heading",
"attrs": { "level": 2 },
"content": [
{ "type": "text", "text": "Your Heading Text" }
]
}
level: 1-6 (h1-h6)
2. Paragraph
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Your paragraph text here." }
]
}
3. Bullet List
{
"type": "bulletList",
"content": [
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "List item 1" }
]
}
]
}
]
}
4. Ordered List
{
"type": "orderedList",
"content": [
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Step 1" }
]
}
]
}
]
}
5. Blockquote
{
"type": "blockquote",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "This is a quote." }
]
}
]
}
6. Code Block (Enhanced)
{
"type": "codeBlock",
"attrs": { "language": "python" },
"content": [
{ "type": "text", "text": "print('Hello World')" }
]
}
- Enhanced with language selector dropdown
- Includes copy button functionality
- Supported languages: javascript, typescript, python, java, csharp, cpp, c, go, rust, php, ruby, swift, kotlin, html, css, scss, json, yaml, xml, sql, bash, shell, powershell, markdown, plaintext
7. Image Gallery
{
"type": "imageGallery",
"attrs": {
"images": [
{
"url": "https://example.com/image1.jpg",
"alt": "Image 1 description",
"caption": "Caption for image 1"
},
{
"url": "https://example.com/image2.jpg",
"alt": "Image 2 description",
"caption": "Caption for image 2"
}
]
}
}
- Supports multiple images in a grid layout
- Each image can have alt text and caption
- Images are displayed in a responsive grid
8. Video Embed
{
"type": "videoEmbed",
"attrs": {
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"caption": "Optional video caption",
"width": 640,
"height": 360
}
}
- Supports YouTube URLs (watch or embed format)
- Supports Vimeo URLs
- Supports direct video files (.mp4, .webm, .ogg)
- Optional caption and custom dimensions
9. Mermaid Diagram
{
"type": "mermaidDiagram",
"attrs": {
"code": "graph TD\n A[Start] --> B[Process]\n B --> C[End]"
}
}
- Supports all Mermaid diagram types (flowchart, sequence, class, state, etc.)
- Code is stored as a string with newlines
- Renders interactive diagrams
- Reference: Mermaid Documentation
Text Formatting (Marks)
Text nodes can have formatting marks:
Bold
{
"type": "text",
"marks": [{ "type": "bold" }],
"text": "Bold text"
}
Italic
{
"type": "text",
"marks": [{ "type": "italic" }],
"text": "Italic text"
}
Inline Code
{
"type": "text",
"marks": [{ "type": "code" }],
"text": "code()"
}
Link
{
"type": "text",
"marks": [
{
"type": "link",
"attrs": {
"href": "https://example.com",
"target": "_blank"
}
}
],
"text": "Link text"
}
Combined Marks
{
"type": "text",
"marks": [
{ "type": "bold" },
{ "type": "italic" }
],
"text": "Bold and italic"
}
Complete Example
See content-template.json for a complete, working example with all node types.
Validation Rules
- JSON must be valid - No syntax errors
- Root must be object - Cannot be an array or primitive
- Content must have type "doc" - Top-level content type
- Content must have content array - Array of child nodes
- Enum values must match - content_type, access_level, difficulty_level
- URLs must be valid - If provided, featured_image and video_url must be proper URLs
- Tags must be array - If provided, tags must be an array of strings
Import Process
- Open Content Editor
- Click "Import JSON" button
- Click "Show Required Schema" to view this reference
- Paste your JSON
- Click "Import Content"
- Fix any validation errors if they appear
- Manually select Category and Course/Track (these are not imported)
- Save or Publish
Common Errors
❌ Using snake_case instead of camelCase
{ "type": "bullet_list" } // Wrong
{ "type": "bulletList" } // Correct
❌ Missing paragraph wrapper in list items
{
"type": "listItem",
"content": [
{ "type": "text", "text": "Item" } // Wrong - no paragraph
]
}
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Item" } // Correct
]
}
]
}
❌ Invalid enum value
{ "content_type": "article" } // Wrong - not in allowed values
{ "content_type": "blog" } // Correct
Need Help?
- View the complete example:
content-template.json - Check validation errors in the import modal
- Refer to TipTap documentation: https://tiptap.dev/