Content and edits
Replace or edit a document’s markdown safely with baseVersion.
A document’s content is GitHub Flavored Markdown: headings, paragraphs, emphasis, links, images, lists, task lists, blockquotes, code blocks, tables and horizontal rules. Writes change the draft; readers see the change after the document is published again. Every write records a revision.
Write safely with baseVersion#
Every document has a version that goes up with each content write. Read the document, make your change, and send the version you read as baseVersion. If someone wrote in between, nothing is written and you get a 409 VersionConflict with the currentVersion. Read the document again, redo your change on the new content, and retry.
Limits#
- A document’s content can be at most 2 MB.
- A
markdownfield can be at most 2,097,152 characters. - The whole request body can be at most 20 MB.
Endpoints#
Replace the content#
/documents/:id/contentReplaces the draft with new markdown and records a revision. Readers see the change after the document is published again.
The response is the document summary with the new version and hasUnpublishedChanges.
idstringrequired- The document’s id.
markdownstringrequired- The whole document as GitHub Flavored Markdown. At most 2,097,152 characters (2 MiB).
baseVersioninteger- The
versionfrom your last read. If the document changed since, nothing is written and you get a 409. Leave it out to overwrite whatever is there. messagestring- A note for the revision history, such as what you changed.
editorStateJsonstring- The web editor’s state, sent by the editor itself. Leave it out.
VersionConflict409baseVersionisn’t the current version. The body hascurrentVersion: read the document again and redo the change.DocumentTooLarge413- The content would be over 2 MB.
NotFound404- No document with this id in the token’s project, or it was deleted.
WritesDisabled503- Content writes without
editorStateJsonare turned off on this server.
curl -X PUT "https://api.pmkin.io/documents/6704a1f0c2b3d4e5f6a7b8c9/content" \-H "Authorization: Bearer $PMKIN_MANAGEMENT_TOKEN" \-H "Content-Type: application/json" \-d '{"baseVersion": 7,"markdown": "# Headless CMS pricing\n\nWhat each plan costs, and when an upgrade pays off.\n\n## Free plans\n\nMost vendors offer one.\n","message": "Add a section on free plans"}'
{"assigneeId": "66f0b2c4d5e6f7a8b9c0d1f0","briefState": "claimed","categoryId": "6701c3d4e5f6a7b8c9d0e1f2","clusterId": "6702d4e5f6a7b8c9d0e1f2a3","contentUpdatedBy": {"agent": "Claude Code","id": "6703f6a7b8c9d0e1f2a3b4c5","name": "Writing agent","type": "token"},"dueDate": "2026-10-20","id": "6704a1f0c2b3d4e5f6a7b8c9","isPublished": false,"slug": "headless-cms-pricing","status": "drafting","title": "Headless CMS pricing","updatedAt": "2026-10-08T09:12:44.000Z","wordCount": 11,"hasUnpublishedChanges": false,"version": 8}
Edit the content#
/documents/:id/content/editsChanges part of the draft without sending all of it. All edits apply, or none do: the first edit that fails stops the request and nothing is written. One revision records them all.
Kinds of edit#
{ "oldText", "newText" }replaces text.oldTextmust match exactly one place in the document, including whitespace and markdown syntax. Copy it from the content you read, with enough around it to be unique. An emptynewTextdeletes it.{ "append" }adds text as a new paragraph at the end.{ "prepend" }adds text as a new paragraph at the start.
Each edit sees the result of the ones before it. Error messages count edits from 1, so Edit 2 failed means the second.
idstringrequired- The document’s id.
editsobject[]required- The edits, applied in order. Each is
{ "oldText", "newText" },{ "append" }or{ "prepend" }. baseVersionintegerrequired- The
versionfrom your last read. Required here, so edits never land on text you haven’t seen. messagestring- A note for the revision history.
BaseVersionRequired400baseVersionis missing.VersionConflict409baseVersionisn’t the current version. The body hascurrentVersion: read the document again and redo the change.EditTextNotFound422- An
oldTextdoesn’t appear in the document. The message names the edit, counting from 1. EditTextNotUnique422- An
oldTextappears more than once. Include more surrounding text. EditInvalid422- An edit has none of
oldTextandnewText,appendorprepend. DocumentTooLarge413- The content would be over 2 MB.
NotFound404- No document with this id in the token’s project, or it was deleted.
WritesDisabled503- Content writes without
editorStateJsonare turned off on this server.
curl -X POST "https://api.pmkin.io/documents/6704a1f0c2b3d4e5f6a7b8c9/content/edits" \-H "Authorization: Bearer $PMKIN_MANAGEMENT_TOKEN" \-H "Content-Type: application/json" \-d '{"baseVersion": 7,"edits": [{"newText": "What each plan costs in 2026, and when an upgrade pays off.","oldText": "What each plan costs, and when an upgrade pays off."},{"append": "## Free plans\n\nMost vendors offer one."}],"message": "Date the intro and add free plans"}'
{"assigneeId": "66f0b2c4d5e6f7a8b9c0d1f0","briefState": "claimed","categoryId": "6701c3d4e5f6a7b8c9d0e1f2","clusterId": "6702d4e5f6a7b8c9d0e1f2a3","contentUpdatedBy": {"agent": "Claude Code","id": "6703f6a7b8c9d0e1f2a3b4c5","name": "Writing agent","type": "token"},"dueDate": "2026-10-20","id": "6704a1f0c2b3d4e5f6a7b8c9","isPublished": false,"slug": "headless-cms-pricing","status": "drafting","title": "Headless CMS pricing","updatedAt": "2026-10-08T09:12:44.000Z","wordCount": 11,"hasUnpublishedChanges": false,"version": 8}