Next CapNext Cap

Helpdesk Content API

Pull your help center's collections and articles — every language included — into your own database and build a fully custom help site on your own domain. Enterprise-only.

Overview

The Helpdesk Content API exposes everything your help desk contains — help centers, the collection tree, and every article in every language — as raw JSON. Pull the content into your own database and render a fully custom help site with your own design, on your own domain. Content endpoints are read-only (GET); authoring stays in the dashboard, and the hosted help center keeps working unchanged alongside it.

Enterprise plan only. Keys on any other plan receive 403 on every endpoint on this page. Organizations below Enterprise use the hosted help center.

Authentication

Use your existing Data API key from Settings → API Keys (the same sk_live_ key the External Data API uses), passed in the X-Api-Key header or as a Bearer token.

Authenticationbash
curl -H "X-Api-Key: sk_live_YOUR_KEY" \
https://api.nextcap.ai/api/v1/external/help/centers
The key is org-private and can read drafts as well as published content. Treat it like a database credential: server-side only, never in a browser bundle or mobile app.

Localized Fields

Localized fields (title, summary, description, body) are locale maps like { "en": "…", "fr": "…" } — one response carries every translation, and article body values are Markdown. To match the hosted help center, treat an article as translated into a locale only when both title[locale] and body[locale] are non-empty, and fall back to the center's default_locale otherwise.

Help Centers

GET/external/help/centersAPI Key

List every help center in your organization (an org can run several, e.g. one per widget).

Response — 200 OKjson
{
"data": [
{
"id": "uuid",
"slug": "acme-support",
"name": "Acme Support",
"description": "How to get the most out of Acme",
"scope": "agent",
"default_locale": "en",
"locales": ["en", "fr", "es"],
"primary_widget_id": "uuid",
"custom_domain": "help.acme.com",
"created_at": "2026-05-01T09:00:00.000Z",
"updated_at": "2026-07-01T14:30:00.000Z"
}
]
}
GET/external/help/centers/:centerIdAPI Key

Get a single help center by ID.

Collections & Categories

GET/external/help/centers/:centerId/collectionsAPI Key

The full collection tree as a flat list. Rebuild the hierarchy via parent_id (null = top level); rows come back in the editor's position order.

localestring

Comma-separated locales to keep in locale-map fields, e.g. en,fr.

sort_bystring

position (default), updated_at, or created_at.

sort_orderstring

asc (default) or desc.

Response — 200 OKjson
{
"data": [
{
"id": "uuid",
"help_center_id": "uuid",
"parent_id": null,
"slug": "billing",
"title": { "en": "Billing", "fr": "Facturation" },
"description": { "en": "Plans, invoices, refunds" },
"icon": "RiBankCardLine",
"position": 0,
"created_at": "2026-05-01T09:00:00.000Z",
"updated_at": "2026-06-20T11:00:00.000Z"
}
]
}
GET/external/help/centers/:centerId/categoriesAPI Key

Legacy second-level grouping under collections. Empty for most organizations — nested sub-collections replaced it. Same position ordering and sort_by / sort_order params as collections.

Articles

GET/external/help/centers/:centerId/articlesAPI Key

Paginated article list. Ordered by updated_at ascending for stable sync walks; pass sort_by=position for the editor's reading order.

statusstring

published (default), draft, archived, or all.

collection_idUUID

Only articles filed under this collection.

category_idUUID

Only articles filed under this category.

updated_afterISO 8601

Incremental sync cursor. Inclusive (updated_at >= cursor), so boundary rows re-deliver instead of skipping — upsert by id.

updated_beforeISO 8601

Upper bound on updated_at.

include_deletedboolean

Include soft-deleted articles (deleted_at set) so you can tombstone local rows. Default false.

pageinteger

Page number (default: 1).

per_pageinteger

Items per page, 1–100 (default: 20).

sort_bystring

updated_at (default), position, created_at, or published_at. See Ordering below.

sort_orderstring

asc (default) or desc.

Response — 200 OKjson
{
"data": [
{
"id": "uuid",
"help_center_id": "uuid",
"collection_id": "uuid",
"category_id": null,
"slug": "getting-started",
"title": { "en": "Getting started", "fr": "Premiers pas" },
"summary": { "en": "Set up your account in five minutes" },
"body": { "en": "## Welcome\n\nFirst, …", "fr": "## Bienvenue\n\n…" },
"cover_image_url": null,
"seo_title": null,
"seo_description": null,
"og_image": null,
"tags": ["onboarding"],
"status": "published",
"visibility": "both",
"position": 0,
"author": { "name": "Jane Doe", "avatar_url": "https://…" },
"published_at": "2026-07-01T10:00:00.000Z",
"created_at": "2026-06-20T09:00:00.000Z",
"updated_at": "2026-07-02T14:30:00.000Z",
"deleted_at": null
}
],
"meta": { "page": 1, "per_page": 20, "total": 58, "total_pages": 3 }
}
GET/external/help/centers/:centerId/articles/:articleIdAPI Key

Get a single article by ID. Soft-deleted articles are returned with deleted_at set, so a webhook consumer reacting to help_article.deleted never hits a 404.

Public visibility on the hosted help center means status = published and visibility of both or helpcenter_only — mirror that filter for parity (widget_only articles belong to the in-chat Help tab, hidden to neither surface).

Ordering

Collections, categories, and articles each carry a position — the manual order your content team sets by dragging rows in Help Desk → Content. It is the order the hosted help center and the in-widget Help tab render in, so honoring it keeps a custom-built site consistent with what your team arranged.

position is a rank within a sibling group, never a global one. Collections group by parent_id, categories by collection_id, articles by collection_id + category_id (articles with a null collection_id form their own unfiled group). Rank 0 means "first among my siblings", so many rows in one center legitimately hold 0 — sort within a group, not across the whole list.

Collections and categories already return in position order. Articles default to updated_at ascending and that default will not change — the incremental sync below walks pages against it. Ask for reading order one sibling group at a time instead:

Articles in the customer's chosen orderbash
curl "https://api.nextcap.ai/api/v1/external/help/centers/CENTER_ID/articles?collection_id=COLLECTION_ID&sort_by=position" \
-H "X-Api-Key: sk_live_YOUR_KEY"

That query is a single group as long as the collection uses no categories — the normal case, since sub-collections replaced them. If a collection does hold categories, either pull one at a time with category_id, or fetch the whole collection and bucket the result by each article's category_id before rendering — within a bucket the rows are already in position order. Articles with no category come back as category_id: null, which is simply another bucket key.

Every sort ends with a unique key, so paging a sorted list never duplicates or skips a row: position breaks ties the way your own help site does (articles by newest published_at, collections and categories by created_at) and then by id; timestamp sorts go straight to id. An unrecognized sort_by or sort_order returns 400.

Keeping Your Copy in Sync

  1. Backfill — page through articles?status=all&per_page=100&page=N until meta.total_pages, plus one call each for collections and categories.
  2. Incremental — remember the newest updated_at you have seen and poll with status=all&include_deleted=true&updated_after=<cursor>. The boundary is inclusive, so upsert by id and repeats are harmless.
  3. Real time — subscribe to the help_* events on the Webhooks page and re-fetch the entity named in the payload. Treat webhooks as the change notification and these GET endpoints as the source of truth.

Webhook Events

Sixteen events cover the content graph: help_center.*, help_collection.*, help_category.* (created / updated / deleted), plus help_article.created / updated / published / deleted, plus help_collection.reordered / help_category.reordered / help_article.reordered. help_article.published fires on the draft → published transition and is the typical "rebuild my public site" trigger. The reordered events carry only the ids whose position moved, so re-fetching that one sibling group is enough. Setup, payload format, signature verification, and retry behavior are on the Webhooks page.

Engagement Beacons (Optional)

The hosted help center records page views and "was this helpful?" votes that power the dashboard's Insights. Your custom frontend can keep that data flowing through the same public, unauthenticated beacons — they are browser-safe and need no API key.

POST/public/help/:centerId/articles/:slug/viewNone

Record one page view. Returns 204.

localestring

Locale the article was read in.

sessionIdstring

Random per-visitor session identifier.

referrerstring

Optional referrer URL.

POST/public/help/:centerId/articles/:articleId/feedbackNone

Record a helpfulness vote.

ratingstringrequired

positive, neutral, or negative.

commentstring

Optional free-text comment.

localestring

Locale the article was read in.

sessionIdstring

Random per-visitor session identifier.