Early preview: Publishing a release with change sets over the API is currently in early preview. This feature is under active development, and its behavior, endpoints, request and response formats, and availability may change in the future without prior notice. We recommend avoiding reliance on this feature for critical production workflows until it reaches general availability.
A change set is a release folder. You put staged article changes, unpublished articles or unpublished translations, and publish the whole thing in one action when your production update is out — so your documentation goes live with the feature it describes, rather than before or after it.
Nothing in an open change set is visible to readers. Removing an item never deletes the work, and deleting a change set never deletes any content — a change set only ever points at work that exists on its own.
Change sets are included in Catalyst, and build on staged changes — stage your article edits first, then group them here.
Two things worth knowing before you build against this
Publishing answers 202, never 200. A release outlives the request that starts it. A 200 would tell your deploy script the documentation is live when the job has not begun, so the response is 202 Accepted with a status_url to poll.
Adding items can answer 207. If part of your batch cannot be added — an article with nothing staged, say — the rest still lands and the response tells you which ids did not. Rejecting the whole batch would make a release depend on every article being in exactly the state you predicted.
Create a release
/v1/change-setsCreate a change set. Name it after the thing it ships with — that is what you will look for later.
/v1/change-setsList change sets on your site, newest activity first.
/v1/change-sets/{changeSetId}Read one change set with its items and its readiness summary.
Fill it
Send article ids and category ids together. Articles contribute their staged changes (every staged language), or a publish flip if they have never been published. Categories contribute a visibility change, which is how you keep a whole section hidden until launch.
/v1/change-sets/{changeSetId}/itemsAdd articles and categories to a release. Answers 207 when part of the batch could not be added.
/v1/change-sets/{changeSetId}/items/{itemId}Take an item out of the release. The staged changes or article it pointed at are kept.
Check it before you ship
readiness separates two very different things, and the distinction is the point of the field:
Blockers stop a publish and cause a
422.conflictmeans the live article changed after the edits were staged;article_goneandcategory_gonemean the work was deleted.Warnings never stop anything — only you know whether they are intentional.
locale_gapmeans an article will publish untranslated;staged_not_addedmeans an article has changes in another language that are not part of this release.
Publish it
/v1/change-sets/{changeSetId}/publishPublish the release, or schedule it. Always answers 202 — the run outlives the request.
/v1/change-sets/{changeSetId}/scheduleCancel a pending schedule. The contents are untouched.
Follow the run
Branch on done, not on the status string. It is computed for you so a polling loop always terminates — including when a release ends up only partly applied.
/v1/change-sets/{changeSetId}/statusPoll a release in progress. Read scope is enough — watching is not changing.
Partial publication is normal
Items apply in independent transactions, so a release can end up partly applied — and the API says so honestly rather than pretending otherwise:
published— every item applied.partially_published— some applied, some did not. Checkitems[].error.failed— nothing applied.
Retrying is just publishing again. Items that already applied are skipped, so nothing is published twice and no watcher is notified twice.
A worked example
Ship the documentation for a feature at the moment the feature goes out:
API=https://api.helpcenter.io/v1
KEY=your-read-write-token
# 1. Open the release.
SET=$(curl -sX POST "$API/change-sets" -H "apikey: $KEY" \
-H 'Content-Type: application/json' \
-d '{"name":"Boards v2"}' | jq -r .change_set.id)
# 2. Fill it with staged articles and the hidden category.
curl -X POST "$API/change-sets/$SET/items" -H "apikey: $KEY" \
-H 'Content-Type: application/json' \
-d '{"article_ids":[4821,4822],"category_ids":[77]}'
# 3. Check nothing is blocking it.
curl -s "$API/change-sets/$SET" -H "apikey: $KEY" | jq .change_set.readiness
# 4. Ship it, and wait for the run to finish.
curl -X POST "$API/change-sets/$SET/publish" -H "apikey: $KEY"
until [ "$(curl -s "$API/change-sets/$SET/status" -H "apikey: $KEY" | jq -r .done)" = true ]; do
sleep 3
doneHousekeeping
/v1/change-sets/{changeSetId}Rename a change set or change its description. Allowed after publishing too — the name is how you find the release in history.
/v1/change-sets/{changeSetId}Delete the release folder. No content is deleted — staged changes stay staged and unpublished articles stay unpublished.
Errors
401— theapikeyheader is missing or unknown.402— change sets are not included in this site's plan.403— a read-scoped token attempted a write.404— the change set belongs to another site, or does not exist.409— the change set is publishing or already published.422— validation failed, or readiness blocked the publish.
For the staged-article endpoints these releases are built from, see Staging article changes over the API.