Content versions

Content versions

A content version is a saved snapshot of a page's body content — the same rows that back GET /pages/{pageId}/content (which always serves the latest one) and POST /pages/{pageId}/content (which creates a new one, or collapses into the latest). This page covers listing and reading version history.

All content-version endpoints require sites:read.

Version ids are NOT append-only. Consecutive manual edits (POST /pages/{pageId}/content without an intervening non-manual change) collapse into the same version row rather than creating a new one — see collapsed on the content POST response. Treat this list as a snapshot of current history, not a stable ledger: don't cache version ids across a save and assume the set you fetched earlier still lines up one-to-one with what actually happened. If you need to know whether your last save produced a new row, read collapsed off that response — don't infer it from a version count.

source values

Source Meaning
manual_edit Written by the editor UI or POST /pages/{pageId}/content
crawl Overwritten by a recrawl re-scraping the live page (POST /pages/{pageId}/recrawl)
outline Produced by accepting generated outline sections
action Produced by an AI action being applied

Other values may appear over time — treat source as an informational string, not a closed enum.


GET /pages/{pageId}/content-versions

List a page's content versions, newest first. Without doc bodies — each item is the lean shape; fetch a specific version's detail endpoint for its rendered markdown.

Scope: sites:read

Path parameters

Parameter Type Description
pageId integer The page's ID

Query parameters

Parameter Type Default Notes
page integer 1 1-indexed. Minimum 1.
limit integer 20 Minimum 1, maximum 100.

Request

curl "https://new.metamonster.ai/api/v1/pages/5001/content-versions?limit=20" \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

Response 200

{
  "data": [
    {
      "id": 9301,
      "source": "manual_edit",
      "status": "draft",
      "word_count": 655,
      "created_at": "2026-08-01T10:00:00Z",
      "updated_at": "2026-08-01T10:00:00Z"
    },
    {
      "id": 9300,
      "source": "crawl",
      "status": "draft",
      "word_count": 640,
      "created_at": "2026-07-20T09:20:00Z",
      "updated_at": "2026-07-20T09:20:00Z"
    }
  ],
  "meta": { "total": 12, "page": 1, "per_page": 20 }
}

Each item (lean content-version shape):

Field Type Description
id integer Content version ID
source string Which write path produced this version — see source values
status string Internal lifecycle status. Currently always draft; reserved for future workflow states.
word_count integer | null Body word count at this version. Populated for every source (including crawl); null only ever appears on rows written before this field existed.
created_at string When this version was created
updated_at string Last update — bumped in place when a later manual edit collapses into this version

Errors

Status When
404 not_found No such page in your organization (Page not found)

GET /pages/{pageId}/content-versions/{versionId}

Fetch one content version with its body rendered as markdown. The underlying ProseMirror document never leaves the API — you only ever get markdown.

Scope: sites:read

Path parameters

Parameter Type Description
pageId integer The page's ID
versionId integer The content version's ID

Request

curl https://new.metamonster.ai/api/v1/pages/5001/content-versions/9300 \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

Response 200

{
  "data": {
    "id": 9300,
    "source": "crawl",
    "status": "draft",
    "word_count": 640,
    "created_at": "2026-07-20T09:20:00Z",
    "updated_at": "2026-07-20T09:20:00Z",
    "body_markdown": "# Pricing\n\nSee our plans below…"
  }
}

Same fields as the list shape, plus:

Field Type Description
body_markdown string This version's body content rendered to markdown. Empty string "" if the stored document is malformed or empty.

Errors

Status When
404 not_found No such page in your organization, or no such content version on that page (Page not found / Content version not found)

Rolling back to a previous version

There's no dedicated rollback endpoint — a rollback is just a normal save whose content happens to be an old version's:

# 1. Fetch the version you want to restore
curl https://new.metamonster.ai/api/v1/pages/5001/content-versions/9300 \
  -H "Authorization: Bearer mm_YOUR_API_KEY"
# → { "data": { "body_markdown": "# Pricing\n\n…", … } }

# 2. Check the page's CURRENT version (so you don't clobber a newer edit)
curl https://new.metamonster.ai/api/v1/pages/5001/content \
  -H "Authorization: Bearer mm_YOUR_API_KEY"
# → { "data": { "content_version_id": 9302, … } }

# 3. Save the old markdown as a new version, guarded by base_version_id
curl -X POST https://new.metamonster.ai/api/v1/pages/5001/content \
  -H "Authorization: Bearer mm_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "markdown": "# Pricing\n\nSee our plans below…", "base_version_id": 9302 }'

This creates a new version (source manual_edit) with the restored content — it doesn't delete or rewrite history, so the version you rolled back from is still there if you change your mind again. Passing base_version_id (the version you read in step 2) makes the restore fail with 409 conflict instead of silently overwriting a page that was edited again between steps 2 and 3.