Knowledge Base API
The Knowledge Base API manages knowledge base articles with rich-text content, categories, access control by visibility and status, view tracking, tags and attachments. Links to tickets/problems/incidents/changes go through the central linking API. Base path: /api/knowledge-base.
🔐 Auth: Logged-in users only; API keys are rejected. Rights via knowledgeBase.*, categories via settings.manageCategories. status and visibility are uppercase in both input and response (PUBLIC/INTERNAL/RESTRICTED, DRAFT/PUBLISHED/ARCHIVED); lowercase is rejected with 400. See RBAC →.
Endpoints — Articles
| Method | Endpoint | Description | Permission |
|---|---|---|---|
GET | /api/knowledge-base/articles | Paginated list, visible articles only; ?deleted=1 = trash | view* (trash: viewDeleted) |
GET | /api/knowledge-base/articles/stats | Counts: published/draft/archived/total | view* |
GET | /api/knowledge-base/tags | Tags with article count ({data}, scoped to visible articles) | ≥1 KB view key |
GET | /api/knowledge-base/articles/:id | Single article (increments viewCount) | view* |
POST | /api/knowledge-base/articles | Create (201, writes revision v1) | create (+publish/archive) |
PUT | /api/knowledge-base/articles/:id | Update (version required → 409 KB_VERSION_CONFLICT; writes revision) | editOwn/editAll (+Transition) |
DELETE | /api/knowledge-base/articles/:id | Soft-delete → trash (links/tags/attachments stay) → 204 | delete |
POST | /api/knowledge-base/articles/:id/restore | Restore from trash (critical) | restore |
GET / POST / DELETE | /api/knowledge-base/articles/:id/grants (+/:subjectType/:subjectId) | Manage RESTRICTED grants (audit GRANT_ADDED/REMOVED) | Edit rights on the article |
GET | /api/knowledge-base/articles/:id/revisions (+/:version, +/:version/restore) | Revision history + snapshot + restore | Edit rights on the article |
* view = the article is not deleted and the caller is either the author or holds both the visibility and the status right. Visibility: viewPublic/viewInternal/viewRestricted resp. a grant for RESTRICTED; status: viewDraft/viewPublished/viewArchived. A role with viewPublished but without viewInternal does not see INTERNAL articles even via direct ID. List and single fetch apply the same rule.
Endpoints — Categories
| Method | Endpoint | Description | Permission |
|---|---|---|---|
GET | /api/knowledge-base/categories | All categories ({data}, +articleCount); query includeInactive | KB-view OR settings.manageCategories |
POST | /api/knowledge-base/categories | Create category (201) | settings.manageCategories |
PUT | /api/knowledge-base/categories/:id | Update | settings.manageCategories |
DELETE | /api/knowledge-base/categories/:id | Delete → 204 (400 if articles exist) | settings.manageCategories |
KBCategory: name (unique, 1–50), description? (max 200), color (#RRGGBB, default #3b82f6), isActive, articleCount. Deleting a category with articles → 400 CATEGORY_HAS_ARTICLES.
Access Model (Visibility and Status)
| Visibility | Visible with |
|---|---|
PUBLIC | knowledgeBase.viewPublic |
INTERNAL | knowledgeBase.viewInternal |
RESTRICTED | knowledgeBase.viewRestricted or a grant: USER = own ID · GROUP = one of the caller’s active groups · ROLE = own role |
| Status | Visible with |
|---|---|
DRAFT | knowledgeBase.viewDraft |
PUBLISHED | knowledgeBase.viewPublished |
ARCHIVED | knowledgeBase.viewArchived |
An article is visible only if the caller holds both the visibility and the status right (or has a grant for RESTRICTED). Exception: the author always sees their own articles, regardless of both rights. A grant replaces only the visibility right — a draft is still visible only to those with viewDraft.
Status Transitions
| Transition | Permission |
|---|---|
| → published (from ≠ published) | knowledgeBase.publish |
| published → draft | knowledgeBase.unpublish |
| → archived (from ≠ archived) | knowledgeBase.archive |
These rights apply in addition to the edit right (editAll, or editOwn for own articles) and are also checked on create whenever the status differs from the DRAFT default — so "create directly as published" requires create + publish.
Create Article
POST /api/knowledge-base/articles
{
"title": "Reset password in the self-service portal",
"summary": "Quick guide for password reset",
"content": "# Password Reset\n\n## Step 1 ...",
"categoryId": "clx-cat-self-service",
"visibility": "PUBLIC",
"status": "DRAFT",
"tags": ["password", "self-service"]
}
Fields: title (5–200), content (10–50,000), summary? (max 500), categoryId (required), visibility (PUBLIC/INTERNAL/RESTRICTED, default INTERNAL), status (DRAFT/PUBLISHED/ARCHIVED, default DRAFT), tags (max 20, each max 50 chars; case-insensitive, existing spelling wins). The INPUT is a list of names; in responses (list, detail, create, update, restore) tags instead carry references of the form { id, name } — the article list filters on the ID (f.tagIds=hasAny:…). Revision snapshots keep the historical NAMES. The author is always the logged-in user. RESTRICTED grants are NOT set here but via the dedicated /grants endpoints. Attachments separately via POST /api/attachments/KB_ARTICLE/:id.
Update Article
PUT /api/knowledge-base/articles/:id
{
"version": 3,
"title": "Reset password (updated)",
"status": "PUBLISHED"
}
version is required (protection against concurrent overwrites, as with tickets): the client sends the last-read version; if someone else saved in the meantime the server answers 409 KB_VERSION_CONFLICT (expected/actual in details) instead of overwriting their change. Every successful PUT increments version and writes a revision. Content fields are optional (at least one required); a status change requires the matching right (e.g. PUBLISHED → publish). Enums in uppercase. Grants are not set here; switching away from RESTRICTED removes existing grants in the same save (audited).
List & Filters
GET /api/knowledge-base/articles?q=vpn&f.status=PUBLISHED&f.categoryId=clx-cat&page=1&per=20&sort=viewCount
The list uses the uniform filter syntax (also for saved views): q (full text), f.status/f.visibility/f.categoryId/f.tagIds, page/per (per default 20, max 100), sort. search, status, visibility, categoryId, limit, sortBy, sortDirection and sortOrder as plain parameters are rejected with 400 LEGACY_QUERY_PARAM_REMOVED. The list contains only articles the caller may see. Full-text search handles word stems and umlauts. Response:
{
"data": [ /* ... */ ],
"pagination": { "page": 1, "limit": 20, "total": 42, "totalPages": 3, "hasMore": true }
}
Grants, Trash & Revisions
- Grants: RESTRICTED articles are opened via grants — subject type USER, GROUP or ROLE. Managed via GET/POST/DELETE /articles/:id/grants (requires edit rights on the article; audit GRANT_ADDED/GRANT_REMOVED). List and detail carry a grantCount; the grant list itself is returned only to users who may edit the article. Roles for the grant picker: GET /api/roles/options (id/displayName/color).
- Soft-delete + trash: DELETE only marks (deletedAt) — links/tags/attachments stay. The trash is GET /articles?deleted=1 (right viewDeleted); POST /articles/:id/restore brings it back (right restore, critical). Deleted articles are 404 everywhere else. After 90 days (default retention period) they are permanently deleted along with their revisions; tags left without articles are removed as well.
- Revisions: Every create/update writes a snapshot (Revision.version == article.version). GET /articles/:id/revisions ({data}, without content) · GET /revisions/:version (full snapshot; unknown = 404 KB_REVISION_NOT_FOUND) · POST /revisions/:version/restore (acts like a normal update: creates a new revision and checks the status rights). All three require edit rights on the article.
Linking to Other Entities
Articles are linked centrally via the linking API to tickets, problems, incidents and changes — e.g. POST /api/linking/tickets/:id/link-article or /api/linking/problems/:id/link-article. On the article the links appear as linkedTickets, linkedProblems, linkedIncidents, linkedChanges.
Visibility check on linking: POST /api/linking/{tickets|problems|incidents|changes}/:id/check-article-visibility ({articleIds[]}) checks per article whether the audience (ticket→customer · incident/problem→reporter · change→requestor+approver) may see it at all — the agent gets a "not visible to {name}" warning before saving. Article titles do not appear in timelines/activities (data minimization); the frontend resolves the title only for articles the viewer is allowed to see.
🔗 Details, status rules and tiered lists: Entity Linking API →.
Permissions (knowledgeBase)
| Permission | Description |
|---|---|
viewPublic / viewInternal / viewRestricted | See articles by visibility (PUBLIC / INTERNAL / RESTRICTED) |
viewDraft / viewPublished / viewArchived | See articles by status (DRAFT / PUBLISHED / ARCHIVED) |
create | Create articles |
editOwn / editAll | Edit own / all articles; also covers managing RESTRICTED grants |
publish / unpublish / archive | Publish / unpublish / archive |
delete | Delete articles (soft-delete → trash, critical, audited) |
viewDeleted / restore | See trash / restore (default ADMIN only) |
Restoring requires two rights: restore for the action and viewDeleted to see the trash — whoever may not see the trash cannot pull anything out of it. The same visibility rule as in the list also applies (including the author exception), so trash and restore cover the same articles. The same holds for deletion: what is not visible cannot be deleted.
Categories (POST/PUT/DELETE /categories) are managed with settings.manageCategories.
KB ↔ tickets/problems/incidents/changes
Attachments (entityType KB_ARTICLE)
Document library (separate entity)
knowledgeBase.* rights matrix