Management API

Errors

Status codes and error bodies, and how to handle them.

Every error is a JSON object with a _tag, which names the error so code can branch on it, and a message, written for people: it says what went wrong and what to do. Show the message to whoever can fix the problem, and branch on the tag.

Response: 422
{
"_tag": "TitleRequired",
"message": "Add a title before publishing. It's shown on your website and in search results."
}
Handling errors
const response = await fetch(url, { headers, signal: AbortSignal.timeout(10_000) })
if (!response.ok) {
const error = await response.json()
if (error._tag === 'VersionConflict') {
// Read the document again, redo the change on top, and retry.
}
throw new Error(error.message)
}

Status codes#

400Bad Request
401Unauthorized
404Not Found
409Conflict
413Payload Too Large
422Unprocessable Entity
500Internal Server Error
503Service Unavailable

Invalid requests#

When a parameter or body field has the wrong type, is out of range or is missing, the response is a 400 with the tag HttpApiDecodeError. issues lists each problem with the field’s path and a tag: Missing, Type or Refinement.

Response: 400 Bad Request
{
"_tag": "HttpApiDecodeError",
"issues": [
{
"_tag": "Type",
"message": "must be a whole number between 1 and 100",
"path": ["limit"]
}
],
"message": "The request is invalid: limit must be a whole number between 1 and 100. Fix the listed fields and try again."
}

Request errors#

BadRequest400
Unauthorized401
NotFound404
RequestEntityTooLarge413
Conflict409
InternalServerError500

A 422 with the tag BadRequest means a rule outside the document workflow failed, such as a category slug that’s taken or an assignee who isn’t on the team. The message names the field and what to change.

Document errors#

Document content and workflow errors have their own tags. The endpoint pages list which ones each endpoint returns.

Version conflicts#

VersionConflict adds currentVersion. Read the document again, redo your change on the new content, and send it with the new version as baseVersion.

Response: 409 Conflict
{
"_tag": "VersionConflict",
"currentVersion": 9,
"message": "This document changed since version 7. The current version is 9. Fetch the document again and reapply your edits."
}

Every document error#

BaseVersionRequired400
RevisionNotFound404
BriefClaimHeld409
BriefClaimed409
BriefClosed409
BriefNotOffered409
BriefNotReady409
NotInReview409
NotScheduled409
PublishNotAllowed409
ScheduleNotAllowed409
StatusLocked409
SubmitNotAllowed409
VersionConflict409
DocumentTooLarge413
ContentRequired422
EditInvalid422
EditTextNotFound422
EditTextNotUnique422
PublishAtInvalid422
PublishAtPast422
ScheduledNeedsTitleAndSlug422
SlugRequired422
StatusInvalid422
StatusRequiresPublish422
StatusRequiresReview422
TitleRequired422
UnscheduleStatusInvalid422
WritesDisabled503
Messages name MCP tools
The messages for StatusRequiresPublish and StatusRequiresReview are shared with the MCP server and name its tools: publish_document and approve_document are POST …/publish and POST …/approve here, and submit_for_review is POST …/submit.

Draft errors#

Confirming a draft checks every field and lists every problem at once in errors, so you can fix them all before you try again.

Response: 422 Unprocessable Entity
{
"_tag": "IntentInvalid",
"errors": [
{ "field": "status", "message": "Pick idea, planned or drafting. Drafts can't be created in review, scheduled or published." },
{ "field": "title", "message": "Add a title. It's shown in lists and on your website." }
],
"message": "This draft can't be created yet. Fix the listed fields and try again."
}