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
draftsarray embedded inGET /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, andschema, if a new draft is created, itsoriginal_valueis 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) |