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

# Changelog TipTap body format for agents

> Exact TipTap JSON examples agents need to draft changelog bodies via the API or MCP.

Changelog bodies are **not Markdown**. The API expects TipTap JSON: a document with `"type": "doc"` and a `content` array of blocks.

## Minimal valid document

```json theme={null}
{
  "type": "doc",
  "content": [
    {
      "type": "paragraph",
      "content": [{ "type": "text", "text": "Hello from this release." }]
    }
  ]
}
```

Empty body:

```json theme={null}
{ "type": "doc", "content": [] }
```

## Paragraph

```json theme={null}
{
  "type": "paragraph",
  "content": [{ "type": "text", "text": "Plain paragraph text." }]
}
```

## Text marks (bold, italic, underline, link)

```json theme={null}
{
  "type": "paragraph",
  "content": [
    { "type": "text", "text": "Normal " },
    {
      "type": "text",
      "text": "bold",
      "marks": [{ "type": "bold" }]
    },
    { "type": "text", "text": ", " },
    {
      "type": "text",
      "text": "italic",
      "marks": [{ "type": "italic" }]
    },
    { "type": "text", "text": ", and " },
    {
      "type": "text",
      "text": "a link",
      "marks": [
        {
          "type": "link",
          "attrs": {
            "href": "https://example.com",
            "target": "_blank"
          }
        }
      ]
    },
    { "type": "text", "text": "." }
  ]
}
```

## Heading (H2 / H3)

```json theme={null}
{
  "type": "heading",
  "attrs": { "level": 2 },
  "content": [{ "type": "text", "text": "What is new" }]
}
```

## Bullet list

```json theme={null}
{
  "type": "bulletList",
  "content": [
    {
      "type": "listItem",
      "content": [
        {
          "type": "paragraph",
          "content": [{ "type": "text", "text": "First item" }]
        }
      ]
    }
  ]
}
```

## Ordered list

```json theme={null}
{
  "type": "orderedList",
  "attrs": { "start": 1 },
  "content": [
    {
      "type": "listItem",
      "content": [
        {
          "type": "paragraph",
          "content": [{ "type": "text", "text": "Step one" }]
        }
      ]
    }
  ]
}
```

## Image

`attrs.src` must be an HTTPS URL (upload via MCP `upload_changelog_image` / `POST /v1/changelog-images`, or use a public URL).

```json theme={null}
{
  "type": "image",
  "attrs": {
    "src": "https://cdn.example.com/changelog/screenshot.png",
    "alt": "New dashboard screenshot"
  }
}
```

### Upload flow

1. Call `upload_changelog_image` / `POST /v1/changelog-images` with `{ "content_type": "image/png" }` (or jpeg/gif/webp).
2. `PUT` the raw file bytes to `upload_url` using the returned `headers`.
3. Put `public_url` into the image node's `attrs.src`.

## YouTube embed

`attrs.src` is required. Missing `src` is rejected (`youtube_missing_src`).

```json theme={null}
{
  "type": "youtube",
  "attrs": {
    "src": "https://www.youtube.com/watch?v=VIDEO_ID",
    "width": 640,
    "height": 360
  }
}
```

## Common mistakes

| Mistake                          | What happens                       |
| -------------------------------- | ---------------------------------- |
| Sending Markdown as a string     | `invalid_content_json`             |
| Missing `"type": "doc"`          | `invalid_content_json`             |
| YouTube node without `attrs.src` | `youtube_missing_src`              |
| Very large `content_json`        | `content_too_large` (500 KB limit) |

## Related

* [Draft changelogs with an agent](/api-mcp-and-embed/draft-changelogs-with-an-agent)
* [Install the Project Echo agent skill](/api-mcp-and-embed/agent-skill)
* [Create and publish changelog entries](/roadmap-and-changelog/create-publish-changelog)
