Drafts

Drafts

A draft is a proposed new value for a single page field — a rewritten title, a new meta_description, revised body content, and so on. Drafts let you stage changes to a page's SEO fields before publishing them.

Each page has at most one active draft per field. Reading drafts requires sites:read; creating or deleting them requires content:write.

Draft fields

The {field} in the write endpoints is one of a fixed set:

Field What it drafts
title The page title (<title>)
meta_description The meta description
h1 The primary H1 heading
primary_keyword The target keyword
body The page body content
image_alt Image alt text
schema Structured data (schema.org)

Any other field name returns 400 invalid_request.

Draft status

A draft's status is one of pending, generating, draft, failed, or published (and possibly others as the product evolves). "Active" drafts — the ones surfaced on page detail and counted in draft_count — are those in pending, generating, draft, or failed.


GET /pages/{pageId}/drafts

List all drafts for a page (every status), ordered by field name. Not paginated.

Scope: sites:read

Path parameters

Parameter Type Description
pageId integer The page's ID

Request

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

Response 200

{
  "data": [
    {
      "id": 3300,
      "field": "title",
      "status": "draft",
      "original_value": "Pricing — Example",
      "draft_value": "Example Pricing: Plans & Costs",
      "published_at": null,
      "created_at": "2026-08-01T10:00:00Z",
      "updated_at": "2026-08-01T10:05:00Z"
    }
  ]
}

There is no meta object — the full list is returned. Each draft:

Field Type Description
id integer Draft ID
field string Which page field this drafts (see Draft fields)
status string Draft status (see Draft status)
original_value string | null The field's value before the draft
draft_value string | null The proposed new value
published_at string | null When the draft was published, if it has been
created_at string | null When created
updated_at string | null Last update

The drafts array embedded in GET /pages/{pageId} is narrower — only active drafts, and only { field, status, draft_value }. Use this endpoint for the complete list with full detail.

Errors

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

PUT /pages/{pageId}/drafts/{field}

Create or overwrite the draft for a specific field. Stores exactly the value you provide — no AI generation. If an active draft already exists for the field, it's overwritten and set to draft status; otherwise a new draft is created.

Scope: content:write

Path parameters

Parameter Type Description
pageId integer The page's ID
field enum One of the draft fields

Request body

Field Type Notes
draft_value string Required. The proposed value. Max 20,000 characters.
curl -X PUT https://new.metamonster.ai/api/v1/pages/5001/drafts/title \
  -H "Authorization: Bearer mm_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "draft_value": "Example Pricing: Plans & Costs" }'

Response

Status Meaning
201 Created A new draft was created
200 OK An existing active draft for the field was overwritten

Both return the draft under data, in the same shape as GET /pages/{pageId}/drafts:

{
  "data": {
    "id": 3300,
    "field": "title",
    "status": "draft",
    "original_value": "Pricing — Example",
    "draft_value": "Example Pricing: Plans & Costs",
    "published_at": null,
    "created_at": "2026-08-01T10:00:00Z",
    "updated_at": "2026-08-01T10:05:00Z"
  }
}

For title, meta_description, h1, and schema, if a new draft is created, its original_value is seeded from the page's latest snapshot.

field=schema: JSON-LD validation

Writing a schema draft runs the value through the same Schema.org validator used by the AI schema tool. Only unparseable JSON blocks the write — a 400 invalid_request with details.draft_value explaining the parse error. Schema.org rule violations (missing @context, missing required/recommended properties for the @type, malformed nested objects) are advisory: the draft still saves, and the response carries a validation object alongside data so you can see what to fix without a second call.

Property checks cover common @types directly (Organization, LocalBusiness, Article, Product, Event, JobPosting, Course, SoftwareApplication, Service, etc.) plus their well-known schema.org subtypes — e.g. MovingCompany, Plumber, Restaurant, and other LocalBusiness subtypes inherit LocalBusiness's required/recommended properties; TechArticle/SocialMediaPosting inherit Article's; ContactPage/AboutPage inherit WebPage's; WebApplication/MobileApplication inherit SoftwareApplication's; School inherits EducationalOrganization, which itself inherits Organization. A @type outside this list (direct or inherited) still saves — validation.warnings carries an advisory noting it wasn't checked, not an error, since it may still be a valid schema.org type.

A blank draft_value (empty string, or whitespace-only) clears the schema field instead of validating — the draft still saves as an empty value, validation is skipped entirely (not present on the response), and there's no parse error since there's nothing to parse.

curl -X PUT https://new.metamonster.ai/api/v1/pages/5001/drafts/schema \
  -H "Authorization: Bearer mm_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "draft_value": "{\"@context\":\"https://schema.org\",\"@type\":\"Organization\",\"name\":\"Example\",\"url\":\"https://example.com\"}" }'
{
  "data": {
    "id": 3301,
    "field": "schema",
    "status": "draft",
    "original_value": null,
    "draft_value": "{\"@context\":\"https://schema.org\",\"@type\":\"Organization\",\"name\":\"Example\",\"url\":\"https://example.com\"}",
    "published_at": null,
    "created_at": "2026-08-16T10:00:00Z",
    "updated_at": "2026-08-16T10:00:00Z"
  },
  "validation": {
    "valid": true,
    "errors": [],
    "warnings": ["Missing recommended property \"logo\" for Organization"],
    "summary": "Schema is valid but has 1 warning to consider."
  }
}

validation is only present on the schema field — other fields' responses are unchanged (no validation key).

Errors

Status When
400 invalid_request field isn't a valid draft field, draft_value is missing or over the length limit, or (for field=schema) draft_value isn't valid JSON
404 not_found No such page in your organization (Page not found)

DELETE /pages/{pageId}/drafts/{field}

Discard a page's draft for a field. Only removes drafts in pending or draft status — a generating, failed, published, or resolved row is left untouched. Idempotent — the response is 204 whether or not anything was actually deleted, so a "successful" delete can be a no-op if the slot is held by an undeletable status. To take over a generating/failed slot, PUT a new value instead.

Scope: content:write

Path parameters

Parameter Type Description
pageId integer The page's ID
field enum One of the draft fields

Request

curl -X DELETE https://new.metamonster.ai/api/v1/pages/5001/drafts/title \
  -H "Authorization: Bearer mm_YOUR_API_KEY"

Response 204

No content. An empty body is returned whether or not a matching draft existed.

Errors

Status When
400 invalid_request field isn't a valid draft field
404 not_found No such page in your organization (Page not found)