How to tell which format an article uses
GET the article:
GET /api/v2/sites/:site_id/articles/:article_id| Field | Current editor | Classic editor |
|---|---|---|
schema_version | 5 | 4 (or omitted on some older records) |
content_blocks | Empty array | Populated blocks |
html_body | Rendered HTML for reading | Rendered HTML for reading |
A newly created article may not report schema_version: 5 until you write HTML with v5_contents. Always write the body with v5_contents for new articles.
Endpoints
| Action | Request |
|---|---|
| Create article (title and placement only) | POST /api/v2/sites/:site_id/articles |
| Read article metadata and rendered HTML | GET /api/v2/sites/:site_id/articles/:id |
| Read editable HTML and etag | GET /api/v2/sites/:site_id/articles/:id/v5_contents |
| Replace editable HTML | PUT /api/v2/sites/:site_id/articles/:id/v5_contents |
| Upload a new image | POST /api/v2/sites/:site_id/articles/:id/v5_image_uploads |
| Update title, tags, published flag, chapter (not the body) | PUT /api/v2/sites/:site_id/articles/:id |
| Delete article | DELETE /api/v2/sites/:site_id/articles/:id |
Send Accept: application/json and JSON bodies on writes. Authenticate with Basic auth (login and API token or password) or an OAuth Bearer token. OAuth tokens need the kb.write scope for v5_contents and image uploads, including GET.
Create an article
POST /articles creates the article record. It does not set the body.
curl -u LOGIN:API_TOKEN \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"article":{"title":"How to reset a password","chapter_id":123,"published":false}}' \
https://YOUR_ACCOUNT.screenstepslive.com/api/v2/sites/SITE_ID/articlesStore the returned id. Next, GET v5_contents (see below). Empty HTML on a new article is expected.
Read editable HTML
Use html_body from GET article when you only need to display the article. Use v5_contents when you will change it.
curl -u LOGIN:API_TOKEN \
-H "Accept: application/json" \
https://YOUR_ACCOUNT.screenstepslive.com/api/v2/sites/SITE_ID/articles/ARTICLE_ID/v5_contentsExample response:
{
"article": {
"id": 12345,
"html": "<div data-doc-type=\"article\"><p>Existing HTML</p></div>",
"schema_version": 5,
"draft": true,
"published": false,
"etag": "\"abc123...\""
}
}htmlis the current-editor document (what the editor stores), not a full HTML page.etagis required on the next PUT. Copy this JSON field exactly into theIf-Matchheader.- Do not send the response
ETagheader if it looks likeW/"...". That weak form does not match and returns 412.
If this request returns 409 with code wrong_schema, the article is classic. Stop and use Updating article content through the API instead.
Update article HTML
PUT replaces the entire document. There is no PATCH on this path.
- GET v5_contents and copy the JSON etag
- Build the full HTML document
Wrap the fragment in
<div data-doc-type="article">...</div>. Prefer starting from the HTML you just fetched and changing only what you need. Do not send<html>,<body>, or inlinedata:images. - PUT v5_contents with If-Match and publish
publishis required and must be inside thearticleobject.truepublishes a new version.falsesaves a working copy. A caller without publish permission who sendspublish: truereceives 403.
curl -u LOGIN:API_TOKEN \
-X PUT \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H 'If-Match: "abc123..."' \
-d '{"article":{"html":"<div data-doc-type=\"article\"><h2>Reset a password</h2><p>Open Settings, then choose Users.</p></div>","publish":false}}' \
https://YOUR_ACCOUNT.screenstepslive.com/api/v2/sites/SITE_ID/articles/ARTICLE_ID/v5_contentsSuccessful response is the same shape as GET, with a new etag. Store that etag for the next write.
After publish: true, confirm "published": true and "draft": false in the JSON. HTTP 200 alone does not prove the article published.
Optional fields on the same article object:
author_note_message— only valid whenpublishis true (stored with the published version).overwrite_connected_editors— default false. If someone has the article open in the live editor, PUT returns 409editing_conflictunless this is true.
Example HTML
Headings, paragraphs, lists, and ScreenSteps blocks are siblings inside the wrapper:
<div data-doc-type="article">
<h2>Reset a password</h2>
<p>Open Settings, then choose Users.</p>
<ol class="ss-block ss-block--steps">
<li class="ss-block--steps__item" data-index="1">
<span class="ss-block--steps__item-title">Select the user</span>
</li>
<li class="ss-block--steps__item" data-index="2">
<span class="ss-block--steps__item-title">Click Reset password</span>
<div class="ss-block--steps__item-body"><p>The user receives an email with a link.</p></div>
</li>
</ol>
</div>Add images
New images do not go through POST /files. Prepare an upload, PUT the file bytes to the signed URL, then include the returned attributes on an <img> in the article HTML.
- Prepare the upload
POST /api/v2/sites/:site_id/articles/:article_id/v5_image_uploads {"v5_image_upload":{"filename":"screenshot.png"}}Allowed extensions: jpg, jpeg, png, gif, svg.
- PUT the image bytes to upload_url
Send any
upload_headersfrom the prepare response. Confirm that PUT succeeded before writing the article. - PUT v5_contents with the image markup
Apply
html_attributesfrom the prepare response (src,data-cloud-asset-id, and related attributes) on the<img>. Image uploads do not change the article etag — reuse the etag from GETv5_contents.
Update metadata without changing HTML
Title, tags, published state, owner, and chapter stay on:
PUT /api/v2/sites/:site_id/articles/:idDo not send html, html_body, or content_blocks on this request. A successful metadata update often returns {} with HTTP 200.
Delete an article
curl -u LOGIN:API_TOKEN \
-X DELETE \
-H "Accept: application/json" \
https://YOUR_ACCOUNT.screenstepslive.com/api/v2/sites/SITE_ID/articles/ARTICLE_IDSuccess is HTTP 204 with no body.
Common errors
| HTTP | Meaning | What to do |
|---|---|---|
409 wrong_schema | The article is classic, not current-editor HTML | Use the content-blocks API instead. Do not convert it with this endpoint. |
| 428 | Missing If-Match | GET v5_contents and send the JSON etag. |
412 stale_content | If-Match does not match the current HTML | GET again and retry the same article id with the new etag. Do not create a second article. |
409 editing_conflict | Someone has the live editor open | Retry later, or send overwrite_connected_editors: true if replacing their session is intentional. |
422 invalid_content | HTML or publish is invalid | Read errors[].detail. publish must be inside article and set to true or false. |
| 403 | Missing permission or OAuth kb.write scope | Use an editor/admin (or equivalent) that can update content. Publish requires publish permission. |
v5_contents and image-upload errors use an array:
{
"errors": [
{"status": "412", "code": "stale_content", "title": "...", "detail": "..."}
]
}Do not use these routes for current-editor articles
POST /api/v2/sites/:site_id/articles/:id/contentsPOST /api/v2/sites/:site_id/articles/:id/html_importcontent_blockson PUT/PATCH articlePOST /api/v2/sites/:site_id/files
Those routes write the legacy block schema, or they convert a current-editor article back to it.