Knowledge Base
Manage articles via the authenticated API, and read published articles from the public widget-facing endpoints.
Kerabie exposes two separate knowledge base surfaces:
/v1/kb/*: authenticated CRUD for your own articles, using an API key (see Authentication). Available on every plan./public/kb/*: read-only, published-only articles for embeddable consumers (the chat widget, the React Native helpdesk package). No API key; scoped by the widget key your embed already uses.
Every published article is also fed automatically into the AI chatbot as answer context, so anything you publish here can be used to answer visitor questions without extra setup.
Authenticated API (/v1/kb)
List articles
GET /v1/kb/articles
Authorization: Bearer ker_live_abc123...Query params
| Param | Type | Description |
|---|---|---|
search | string | Full-text search across title and content |
category | string | Filter by category |
page | number | Page number (default: 1) |
limit | number | Results per page (default 20) |
Response
{
"data": [
{
"id": 12,
"title": "How to reset your password",
"content": "<p>Go to the login page and click Forgot Password...</p>",
"type": "faq",
"category": "Account",
"status": "published",
"imageUrl": "https://cdn.kerabie.com/knowledge-base/42/12-1234.jpg",
"views": 245,
"helpfulPct": 92,
"votes": 30,
"aiCitations": 88,
"createdAt": "2026-03-15T10:00:00Z",
"updatedAt": "2026-03-15T10:00:00Z"
}
],
"meta": { "total": 43, "page": 1, "limit": 20, "hasMore": true }
}content is HTML: the dashboard editor, the chat widget and the apps all store and show it that way. Plain text sent through the API or a CSV import is shown as-is, so send HTML (<p>…</p>) for paragraphs and formatting.
helpfulPct is the share of widget visitors who answered "Was this helpful?" with yes, and stays null until at least 3 have voted. aiCitations counts the AI chatbot answers that cited the article.
Stats
GET /v1/kb/stats{ "total": 43, "published": 38, "drafts": 5, "views": 12840, "top": { "title": "How to reset your password", "views": 1240 }, "categories": ["Account", "Billing"] }Insights: what to write or fix next
GET /v1/kb/insights{
"mostViewed": [{ "id": 12, "title": "How to reset your password", "views": 1240, "pct": 100 }],
"gaps": [{ "question": "okta sso", "count": 23 }],
"lowestRated": [{ "id": 7, "title": "Do you offer refunds?", "helpfulPct": 74, "votes": 12 }],
"stale": [{ "id": 9, "title": "Connect WhatsApp", "age": "4 months" }]
}gaps are customer questions in the last 30 days that the AI had no article to answer from. lowestRated needs at least 3 votes per article. stale lists published articles not updated in 90 days. Cached for a few minutes.
Get an article
GET /v1/kb/articles/:idCreate an article
POST /v1/kb/articles{
"title": "How to reset your password",
"content": "<p>Go to the login page...</p>",
"category": "Account",
"type": "faq",
"status": "published"
}type is one of faq | article | news | information (default article). status is one of draft | published | archived (default published).
Update an article
PATCH /v1/kb/articles/:idAccepts the same fields as create; only send what's changing.
Delete an article
DELETE /v1/kb/articles/:idPublic, widget-facing API (/public/kb)
No API key. Authenticate with your widget key, either as an x-widget-key header or a widgetKey query param, the same key your chat widget embed already uses.
List published articles
GET /public/kb/articles?widgetKey=wk_yourorg_abc123&search=refundQuery params
| Param | Type | Description |
|---|---|---|
search | string | Full-text search |
category | string | Filter by category |
type | string | Filter by faq | article | news | information |
page / limit | number | Pagination |
Returns only status: "published" articles, the same { data, meta } shape as the authenticated list.
Get a published article
GET /public/kb/articles/:id?widgetKey=wk_yourorg_abc123Increments the article's view count.
Rate an article
POST /public/kb/articles/:id/feedback?widgetKey=wk_yourorg_abc123
{ "helpful": true }The "Was this helpful?" vote from the widget and the React Native package. A visitor can vote up to 3 times per article per day (429 after that); 404 for a draft or unknown article. Votes feed the helpfulness shown in the dashboard.
The chat widget's built-in search screen calls a simpler variant of this, GET /public/knowledge-base?widgetKey=...&q=..., returning { items: [...] }; that's what actually powers the widget UI. The /public/kb/* endpoints above exist for consumers that need pagination or a single-article lookup, like the React Native helpdesk package.
Importing content
Import, crawl, and refine are dashboard actions, authenticated with your logged-in session (not an API key); they live under /knowledge-base/*, not /v1/kb/*. They're documented here because they're part of the same feature, not because they're callable with a ker_live_ key.
Three ways to get content into the knowledge base beyond typing it manually; all AI-assisted and gated by plan (see below).
Upload a document
POST /knowledge-base/import/document
Content-Type: multipart/form-dataUpload a file (max 5MB). Everything becomes drafts for you to review.
.csv: one article per row, no AI step and no AI quota used. Use a header row withtitle(orquestion) andcontent(oranswer);categoryandtypeare optional. Up to 500 rows; rows that can't be used are returned inskippedwith their row number..docx,.md,.txt,.pdf,.json: AI structures the text into one or more draft articles.
Crawl a website
A two-step flow: you pick which pages get imported before anything runs:
POST /knowledge-base/crawl/discover
{ "url": "https://docs.yoursite.com" }Returns candidate pages found on that domain (from on-page links and, when present, sitemap.xml):
{ "pages": [{ "url": "https://docs.yoursite.com/faq", "title": "FAQ" }] }POST /knowledge-base/crawl/import
{ "urls": ["https://docs.yoursite.com/faq"] }Runs as a background job (crawling and AI structuring can take a while for several pages) and responds immediately with a job ID:
{ "jobId": "42" }Poll for completion:
GET /knowledge-base/jobs/:jobId{ "status": "succeeded", "result": { "imported": 4, "items": [...] } }Refine an article with AI
POST /knowledge-base/:id/refineStreams the refined content back as Server-Sent Events (data: { "delta": "..." } chunks, ending with data: { "done": true }) and saves the result once the stream completes. AI-generated text never uses em dashes.
Plan limits
Import, crawl, and refine share one monthly AI-operations budget per organisation, plus crawl has its own per-run page cap:
| Plan | AI ops / month | Pages per crawl |
|---|---|---|
| Free | Not available | Not available |
| Basic | 10 | 20 |
| Pro | 50 | 100 |
| Enterprise | Unlimited | Unlimited |
Exceeding either limit returns a 403 with a message naming the limit.