Publishing API v2
Use v2 for new article integrations. Draft upload and final submission are separate operations. Public reading and channel administration retain their existing APIs.
Quick start
Create a draft with its primary translation, upload images with page_slug, save the other translations in batches, verify them, then submit status with the exact expected_languages set. A 202 response means review has started, not that publication is complete.
POST /api/v2/channels/demo_channel/pages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Idempotency-Key: article-2026-01:create
{
"slug": "example_article",
"default_language": "en",
"translations": [{
"language": "en",
"title": "Example article",
"excerpt": "A separate summary.",
"content_markdown": "Introduction.\n\n## Section\n\nBody."
}]
}
Each JSON write accepts at most 20 translations and 2 MiB (2,097,152 bytes), both limits apply. An article supports up to 700 translation records; this is a capacity limit, not a promise of 700 supported languages. Oversized requests return 413 before saving anything.
PUT /api/v2/channels/demo_channel/pages/example_article/translations
Idempotency-Key: article-2026-01:batch-2
Content-Type: application/json
{"translations":[{"language":"fr","title":"Exemple","content_markdown":"Introduction.\n\n## Section\n\nTexte."}]}
PATCH /api/v2/channels/demo_channel/pages/example_article/status
Idempotency-Key: article-2026-01:publish
Content-Type: application/json
{"status":"published","expected_languages":["en","fr"]}
GET article returns a compact summary. GET translations returns metadata with cursor pagination (up to 100 per page). GET translations/{language} returns one body; formats[]=html and formats[]=markdown select formats. view=working reads a pending revision without changing the public version.
content_sha256 hashes saved normalized HTML, not the input Markdown. payload_sha256 covers title, excerpt, HTML, SEO fields and og_image_path. revision increments when that content changes, not when status changes. A hash does not replace quality and image checks.
API v2
GET /api/v2/channelsGET /api/v2/channels/{channel}/pagesPOST /api/v2/channels/{channel}/pagesGET /api/v2/channels/{channel}/pages/{article}GET /api/v2/channels/{channel}/pages/{article}/translationsPUT /api/v2/channels/{channel}/pages/{article}/translationsGET /api/v2/channels/{channel}/pages/{article}/translations/{language}PUT /api/v2/channels/{channel}/pages/{article}/translations/{language}PATCH /api/v2/channels/{channel}/pages/{article}/statusPATCH /api/v2/channels/{channel}/pages/{article}/reviewPATCH /api/v2/channels/{channel}/pages/{article}/settingsPOST /api/v2/channels/{channel}/mediaIdempotency-Key
Every v2 write requires Idempotency-Key. Retry the same method, path and identical JSON bytes with the same key. A changed request needs a new key; reusing a key for different data returns 409. The replay returns the original result; use GET for current status.
Article lifecycle
Bulk review runs in batches of 20 on a lower-priority queue. GET exposes progress and manual-review state. PATCH review with paused=true pauses new work; paused=false resumes or recovers pending work. An already running provider request may finish. Notifications wait for the publication set.
v1 → v2
Migration: keep v1 clients unchanged until their verifier supports v2. Replace the final full GET with summary, paginated metadata and individual body checks. Persist progress and keys. Split 413 batches; if one translation is too large, stop. Honor Retry-After on 429; never blindly repeat publication.
API v1 remains supported with full responses. It is not deprecated and has no retirement date. API v1
Public Content API
The Public Content API is a separate read-only interface. It needs no API key and returns only published channels, articles, and translations.
GET /api/public/v1/channels
GET /api/public/v1/search?q=publishing