helpcenter_apply_template_theme
Start the draft from a ready-made theme — the Template Editor's "Compare & apply": copy all of a theme, or only some of its sections, onto the draft.
A help center's design is its v2 template: theme tokens (colours for light and dark mode, fonts, radius, density), six page kinds (home, category, article, search, contact, notFound), each built from six regions (header, hero, sidebar, main, footer, utility) holding ordered components, plus a global navigation menu, custom CSS and scripts. You edit a DRAFT — the same draft the dashboard's Template Editor opens, with a live preview — and nothing reaches visitors until helpcenter_publish_template. Only v2 help centers can be edited: a classic (v1) one answers template_migration_required, and migrating is the owner's decision, made in the dashboard.
With no `sections`, the draft takes the whole theme: its brand block, colours, fonts, radius, density, every page's layout and components, navigation, scripts, SEO fields and custom CSS — replacing what the draft had (component ids change). To give the current design a theme's LOOK without its layout, name the sections: ['theme.colors', 'theme.darkColors', 'theme.fonts', 'theme.radius', 'theme.density'].
Nothing goes live: the result is a draft to refine with the design edit tools (settings, components, regions, CSS, scripts, navigation) and review before publishing. Read the template again afterwards — ids and structure changed.
Args:
- theme (string): key from helpcenter_list_template_themes.
- sections (string[], optional): brand, theme.colors, theme.darkColors, theme.fonts, theme.radius, theme.density, pages.home, pages.category, pages.article, pages.search, pages.contact, pages.notFound, globals.navigation, globals.scripts, meta, customCss.
- etag (string, optional): refuse if the draft changed since you read it.
Returns: the applied sections, warnings and the new draft status (with etag).
helpcenter_bulk_create_articles
Create or upsert many articles in one request. Use this for imports and migrations instead of calling helpcenter_create_article in a loop. Send at most 50 articles per call; split a larger import into batches of 50.
Requires a write-scoped API key. Give every item an external_id: the batch is then replayable, so a run that dies halfway can simply be sent again — what exists is updated, what is missing is created, and nothing is duplicated.
Args:
- articles (array, required, 1-50): each item takes the same fields as helpcenter_create_article (title required, plus content, slug, category_id, categories, type, visibility, published, external_id, content_format, rehost_images). rehost_images is per item, ON by default through this connector, and all items share one image-download time budget.
Returns: HTTP 207 — { status: "success", results: [...], meta: { total, created, updated, failed } }, one result per item in the order sent. A success is { index, status: "created" | "updated", article, images }. images summarises the external images found in its content: { rehosted, reused, failed: [{ src, reason }], failed_count }, where rehosted counts the images copied into the help center, reused the ones it already held, and failed_count the ones that could not be copied; failed lists their source and reason, and on a very long list stops short of failed_count. The article is saved even when failed_count is above 0, so check it. images is absent when the item had no content or rehost_images was false. A failure is { index, status: "error", external_id, error: { code, message } }. index is the item's position in your articles array: match outcomes to items by index, because a success does not echo external_id at the top level (it is article.external_id). A partly-failed batch is the NORMAL result, not an exception: check meta.failed and read every result whose status is "error" rather than assuming success. One bad item never discards the work of the rest.
Errors: 403 if the key is read-scoped or your role cannot create articles. Otherwise items fail individually, and error.code says why:
- "validation_error": the item was refused as sent; error.errors lists the problem with each field.
- "invalid_argument": a value the site cannot take, such as a language that is not enabled for it.
- "capability_forbidden": your role cannot do what the item asks (publish it, file it in a category, set its visibility, or write to an article it cannot see); error.capability names the permission and error.message the reason.
- "publication_forbidden": the item's external_id belongs to a published article and your role cannot publish; stage the change with helpcenter_stage_article_changes for the article in error.staged_endpoint instead.
- "external_id_busy": that key already belongs to a different live article.
- "persist_failed": the save failed on the server; send the item again (safe when it has an external_id).
helpcenter_create_article
Create a new article in the connected HelpCenter.io help center.
Requires a write-scoped API key (read-scoped keys get a permission error). Titles, content, and slugs are per-language objects keyed by language code. Slugs auto-generate from the title when omitted.
Args:
- title (object, required): per-language title, e.g. {"en": "Getting started"}.
- content (object, optional): per-language body.
- slug (object, optional): per-language URL slug (auto-generated from title if omitted).
- category_id (number, optional): primary category id, or 0 for uncategorized.
- categories (number[], optional): additional category ids to attach.
- type ('article' | 'faq', optional): default 'article'.
- visibility ('public' | 'private' | 'link_only', optional): default 'public'.
- published (boolean, optional): true publishes immediately, false (default) keeps a draft.
- external_id (string, optional): a stable key you own. Sending it makes this call an UPSERT — the same key twice updates the article it created instead of creating a second one. Use it whenever a run might be retried.
- content_format ('html' | 'markdown', optional): defaults to 'html'. If you are writing markdown, you must set this or the raw markdown is stored as the body.
- rehost_images (boolean, optional): ON by default through this connector. Copies the images the content references from other hosts (and inline data: images) into this help center's own storage and points the article at the copies, so it no longer depends on the source site. 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.
Returns: { status: "success", action: "created" | "updated", article: {...}, images? }. HTTP 201 on create, 200 when an external_id matched an existing article. images — { rehosted, reused, failed, failed_count } — is present whenever content was processed for images; a failed image keeps its original URL, so check failed before reporting the import complete.
Errors: 403 if the key is read-scoped; 400 if a language code is not enabled for the site or a category id does not belong to the site; 409 if the external_id already belongs to a different article (it is deliberately not re-pointed — that would make your next replay overwrite the wrong article). 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.
helpcenter_list_articles
List and browse a HelpCenter.io help center's articles, optionally filtered by category, status or last update, and ordered by views.
Use this to browse "what's in category Y" or "the most-viewed articles", or to walk every article for an audit, a backup or an incremental sync, rather than to search for specific text (use helpcenter_search_articles for that). Read-only. Paginated.
Args:
- category_id (number, optional): restrict to one category id.
- status ('published' | 'draft', optional): only published articles, or only drafts. Omit for both.
- updated_since (string, optional): only articles updated at or after this date or date-time, e.g. '2026-09-01' or '2026-09-01 14:30:00' — the updated_at format items come back in. For an incremental sync pass the newest updated_at from your previous pass; the bound is inclusive, so de-duplicate by id.
- order_by ('views', optional): only 'views' is supported; omit for default (recently updated).
- order_type ('asc' | 'desc', optional): sort direction when order_by is set (default 'desc').
- lang (string, optional): language code for returned text (defaults to the site default).
- include_content (boolean, optional): default false, so each article comes back WITHOUT its body: id, external_id, title, slug, type, category_id, categories, published, visibility, views, has_staged_changes, staged_locales, staged_updated_at, updated_at and content_length (the body's length in characters, per language). That is the inventory for deciding what to read in full with helpcenter_get_article. true adds every language's full body, for an export, a backup or a content audit.
- limit (number, optional): items per page, 1-100 (default 100).
- page (number, optional): page number (default 1).
- response_format ('markdown' | 'json'): default 'markdown'.
Returns: { total, count, page, per_page, total_pages, has_more, next, items } — items carry the fields listed under include_content, or with include_content: true the full article objects (see helpcenter_search_articles), every language's body included. A page of long articles with bodies can come to several megabytes.
Paging: every response carries next: { page, limit } — the exact arguments that fetch the first item it did not return — or null when nothing is left. Follow next, with the same filters, instead of computing page + 1 yourself. A response is capped at 25000 characters, in its text and in its structured data alike, and 5.0 MB in all: when a page does not fit, only its first items are returned (truncated: true, count says how many) and next points at the rest, usually with a smaller limit and a later page number. Requesting page + 1 with your original limit would skip them. With include_content: true, a page first cuts every body to a plain-text excerpt before withholding any article (those items carry content_truncated: true; read the full body with helpcenter_get_article). Without bodies, the default, far more articles fit in each response.
Errors: auth error if the key is missing/invalid; validation error if category_id is not a category of this site, or if status or updated_since is not a value the API accepts.
helpcenter_publish_staged_changes
Apply staged changes to the live article, making them visible to readers.
Staged changes let you edit a PUBLISHED article without readers seeing it, then release it deliberately. Staged content is invisible to everything public: the rendered help center, sitemap, site search, the widget, the AI answer path, and this API's read endpoints.
Staged versions are held per article AND per language, so an English hot fix is never held back by an in-progress Portuguese translation.
Publishing archives the outgoing live values (so it is reversible via helpcenter_list_article_versions), applies the staged fields, creates a slug redirect if the slug changed, re-indexes for search, refreshes AI embeddings, and deletes the staged copy.
This releases ONE article. To release several articles' staged edits together, or at a set time, group them in a change set (helpcenter_create_change_set) instead of calling this in a loop.
Args:
- article_id (number, required).
- locale (string, optional): publish only this language; omit to release every staged language at once.
- force (boolean, optional): see below. Do not set it reflexively.
- change_note (string, optional, up to 2,000 characters): why these edits go live now, 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.
Returns: { status: "success", published_locales: [...], article: {...} }.
Errors: 409 BASE_CHANGED means somebody edited the LIVE article after your edits were staged, and publishing would lose their change. The check is per field and idempotent-aware, so it only fires when something would actually be lost. Three ways out: re-read the article and re-stage on top of the newer live version; discard your staged copy; or repeat with force: true to overwrite their edit deliberately. Also 422 ARTICLE_UNPUBLISHED if the article has since been taken down (staged work is kept — republish the article and it becomes publishable again), and 422 if sibling languages disagree on a shared 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.
helpcenter_search_articles
Full-text search a HelpCenter.io help center's articles by query string, returning ranked matches.
This performs keyword search (Meilisearch-backed) over published article titles and content for the connected help center. Use it to answer "find the article about X" intents. It is read-only and does not modify anything. For browsing by category rather than searching, use helpcenter_list_articles.
Args:
- query (string, required): search text matched against titles and content.
- lang (string, optional): language code to search within (defaults to the site default).
- category_id (number, optional): restrict to one category id.
- include_content (boolean, optional): default false, so each match comes back WITHOUT its body (the fields are listed under helpcenter_list_articles). Read the matches you need with helpcenter_get_article. true adds every language's full body.
- limit (number, optional): items per page, 1-100 (default 100).
- page (number, optional): page number (default 1).
- response_format ('markdown' | 'json'): default 'markdown'.
Returns: a payload with { total, count, page, per_page, total_pages, has_more, next, items }, ranked best match first. Each item is an article without its body (see include_content), or with include_content: true the full article (id, per-language title/slug/content, category_id, categories, type, published, visibility, views, ratings, timestamps).
Paging: every response carries next: { page, limit } — the exact arguments that fetch the first item it did not return — or null when nothing is left. Follow next, with the same filters, instead of computing page + 1 yourself. A response is capped at 25000 characters, in its text and in its structured data alike, and 5.0 MB in all: when a page does not fit, only its first items are returned (truncated: true, count says how many) and next points at the rest, usually with a smaller limit and a later page number. Requesting page + 1 with your original limit would skip them. With include_content: true, a page first cuts every body to a plain-text excerpt before withholding any article (those items carry content_truncated: true; read the full body with helpcenter_get_article). Without bodies, the default, far more articles fit in each response.
To answer a question from the help center, search, then read the best one to three matches with helpcenter_get_article.
Errors: returns an auth error if the key is missing/invalid; a validation error if category_id is not a category of this site.
helpcenter_stage_article_changes
Save an edit to a published article WITHOUT readers seeing it. Nothing goes live until you call helpcenter_publish_staged_changes.
Staged changes let you edit a PUBLISHED article without readers seeing it, then release it deliberately. Staged content is invisible to everything public: the rendered help center, sitemap, site search, the widget, the AI answer path, and this API's read endpoints.
Staged versions are held per article AND per language, so an English hot fix is never held back by an in-progress Portuguese translation.
Prefer this over helpcenter_update_article whenever the article is already published and the change should not appear the instant you write it — a rewrite in progress, a coordinated multi-language update, anything wanting review.
This is a PATCH over the staged copy: fields you omit keep whatever was staged before, they are not cleared. Unlike the live article endpoints, the text fields here are plain strings, because a staged version IS one language — named by the required `locale`.
Args:
- article_id (number, required): must be a PUBLISHED article.
- locale (string, required): the language this version is for.
- title, content, slug (strings, optional): a title-only change does NOT rename the URL; send slug to rename. The redirect from the old address is created at publish, never here — so a staged rename cannot redirect live traffic while still private.
- category_id, categories, visibility (optional): these belong to the ARTICLE, not a language. Sibling staged languages published together must agree on them, or publish refuses with 422 naming the field and the two locales.
- release_translation (boolean, optional): mark this language released when the change is published.
- etag (string, optional): pass the one from your last read; a mismatch returns 409 STALE_ETAG with the current value, meaning somebody else moved the staged copy — re-read, re-apply, retry.
- 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.
Returns: { status: "success", staged: { locale, fields, etag, base_signature, updated_at, _links } }.
Errors: 422 NOT_PUBLISHED if the article has never been live (use helpcenter_update_article — its own content IS the draft); 403 STAGING_UNAVAILABLE if the help center's plan does not include staged changes (fixable only by changing the subscription, not the request); 409 STALE_ETAG on a lock mismatch. 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.