Update HelpCenter Article
helpcenter_update_articleUpdate an existing article by id in the connected HelpCenter.io help center.
Partial update: only the fields you pass are changed. Requires a write-scoped API key. Per-language fields (title, content, slug) are objects keyed by language code and merge per language.
Args:
article_id (number, required): id of the article to update.
title, content, slug (objects, optional): per-language fields to set.
category_id (number, optional): primary category id.
categories (number[], optional): replace the set of additional categories.
type ('article' | 'faq', optional).
visibility ('public' | 'private' | 'link_only', optional).
published (boolean, optional): true publishes, false reverts to draft.
external_id (string, optional): adopt this article under a stable key you own, so later upserts by that key hit this article.
content_format ('html' | 'markdown', optional): defaults to 'html'. Set 'markdown' when sending markdown, or the raw markup is stored as the body.
rehost_images (boolean, optional): ON by default through this connector. Copies externally hosted images in the content you send into this help center's storage (see helpcenter_create_article). Send false to keep the original image URLs.
change_note (string, optional, up to 2,000 characters): why you are making this change, in a sentence or two of plain text. TEAM-ONLY: the team reads it beside the edit in the dashboard's Overview; it is never in a response, a webhook, search, or anything a reader sees. Give one whenever you change content.
change_refs (array, optional, at most 5): links to what asked for the change — a ticket, a pull request, a release note — each { label (up to 80 characters), url (https on a public host name; not an IP address or localhost, no user:password@) }. Team-only, like change_note.
notes (array, optional, at most 20): private team notes on passages of the text THIS call writes, each { quote, note, lang }. quote: the passage as PLAIN TEXT exactly as it will read in the new content you send (not Markdown or HTML), occurring there exactly once. note: 1-5000 characters, what you changed and why. lang: the language of that content — required when this call writes more than one language's content, optional when it writes one.
annotate_changes ({ note }, optional): ONE private note per language whose content this call changes, highlighting what changed against the live text it replaces — every added block whole, and in each edited block the span from its first to its last changed word — with note (1-5000 characters) as your reason. A language whose content does not change gets no note.
IMPORTANT — this writes LIVE. On a published article the change is visible to readers immediately. To prepare an edit privately and release it deliberately, use helpcenter_stage_article_changes and helpcenter_publish_staged_changes instead.
NOTES ON WHAT YOU CHANGE: notes and annotate_changes put your reason on the passage itself, so a reviewer sees the change and why in place. The notes are PRIVATE — the team sees them highlighted in the editor; readers never do — so never repeat one into reader-facing text.
They need the notes.write scope ON TOP of what the write needs (it is separate from content access, and an API key holds it only if it was issued with it), and the account's dashboard access to team notes. Without them the call is refused with 403 insufficient_scope, role_forbidden or notes_forbidden, and NOTHING is written.
ALL OR NOTHING: if any quote is refused, nothing is written — no content, no staged version, no revision, no note, no re-hosted image. Fix the note and send the WHOLE call again.
NOT IDEMPOTENT with notes: repeating a call that succeeded leaves its notes a second time. Read them back with helpcenter_list_article_notes before retrying.
422 refusals name the field at fault (e.g. notes.0.quote): note_quote_not_found — the quote is not in the new text (a passage that is only in the text being replaced cannot be noted); note_quote_ambiguous — it occurs more than once (occurrences says how often): quote more of the sentence; note_lang_required — the call writes several languages and a note has no lang; note_locale_not_written — a note names a language this call writes no content for. For a passage already in the article, use helpcenter_create_article_note.
ONE NOTE PER PASSAGE: a passage carries one note's highlight. Two notes of one call may not quote overlapping text (422 note_quotes_overlap). With both fields, each note keeps its quote and annotate_changes highlights the rest of the change; if your notes quote EVERY change in a language, annotate_changes would have nothing left and the call is refused (422 annotate_changes_covered): leave it out, or quote less.
Returns: { status: "success", article: {...}, images? } with the updated article; images reports re-hosted and failed images as for helpcenter_create_article. With notes or annotate_changes, the response also carries notes: [every note this call created, each { id, lang, note, anchor: { mark_id, quote, highlighted }, author, via }] and, with annotate_changes, annotate_changes: [{ lang, status: "annotated" | "skipped", note_id, highlighted, passages, unplaced_passages, reason }]. reason is "unchanged" on a skipped language, or why an annotated note has no highlight: "nothing_to_highlight" (only removals, or changes with no text such as an image), "not_located" (a changed passage could not be pinned to one place), "too_long" (too large to compare word by word). A response WITHOUT notes means the HelpCenter.io API is older than this connector: it ignored both fields and wrote the content without any note. The result then says so, and carries notes_warning.
Errors: 403 if the key is read-scoped; 404 if the article id is not in this help center; 400 for a language code the site does not have; 422 (validation_error) for an invalid category id or a malformed field. A change_note or change_refs the API refuses (too long, too many links, a url that is not https on a public host) refuses the whole call, and nothing is written. With notes or annotate_changes, also the 403 and 422 refusals above.
Tool call template
Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.
{
"id": 1,
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"arguments": {
"article_id": "<article_id>"
},
"name": "helpcenter_update_article"
}
}Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| slug | No | Per-language URL slug. Auto-generated from the title if omitted. | |
| type | No | Content type (default 'article'). | |
| notes | No | Private team notes on passages of the text THIS call writes, at most 20: say on the passage itself what you changed and why. Each quote must occur exactly once in the new text. Needs the notes.write scope, and if any quote is refused nothing at all is written. | |
| title | No | Per-language title to set. | |
| content | No | Per-language article body (HTML/markdown as your site uses). | |
| site_id | No | Which help center to act on: an id from helpcenter_list_sites. Needed when this connection reaches more than one help center; omit it when it reaches one. Applies to this call only — pass it on every call of a task, and ask the user which help center they mean if their request does not say. | |
| published | No | true publishes the article, false keeps it as a draft. | |
| article_id | Yes | Id of the article to update. | |
| categories | No | Additional category ids to attach (multi-category). All must belong to this site. | |
| visibility | No | Visibility: 'public', 'private' (team only), or 'link_only' (shareable token URL). | |
| category_id | No | Primary category id, or 0 for uncategorized. Must belong to this site. | |
| change_note | No | Why you are making this change, in a sentence or two of plain text, up to 2,000 characters, e.g. "Pro plan renamed Growth in the 4.2 pricing." TEAM-ONLY: kept beside the edit in the dashboard's Overview, never in an API response, a webhook, search or anything a reader sees. Give one whenever you change content. | |
| change_refs | No | Up to 5 links to what asked for this change — a ticket, a pull request, a release note — each { label, url }. Team-only, like change_note. | |
| external_id | No | A stable key you own (a source filename, CMS id, repo slug). Makes writes idempotent: sending the same key again updates the article it created instead of creating a second one, so an interrupted run can simply be replayed. Strongly recommended whenever you may retry. | |
| rehost_images | No | Copy images the content references from other hosts (and inline data: images) into this help center's own storage, and point the article at the copies. ON by default through this connector; send false to keep the original image URLs. The response's `images` reports what was re-hosted and what failed. | |
| content_format | No | Format of the `content` you are sending. Defaults to 'html'. Set 'markdown' when content is markdown and the API will convert it — sending markdown without this stores the raw markup as the article body. | |
| annotate_changes | No | Leave ONE private note per language whose content this call changes, highlighting what changed against the live text it replaces: every added block whole, and in each edited block the span from its first to its last changed word. Content that does not change gets no note. Needs the notes.write scope. |