External KB API
Most of Atender’s Knowledge Base is managed in the in-app editor. But for teams that prefer doc-as-code workflows — the same way they manage application code — Atender exposes a stable, scope-gated v1 API at /api/v1/kb/*. You authenticate with a tenant API key, you call the endpoints, and your KB stays in sync with whatever upstream source of truth you keep.
This is how Atender keeps its own help center current. Articles live as markdown in a vault, a small Python script reads them on every change, and /api/v1/kb/* creates or updates them in the live KB. Embeddings rebuild server-side automatically.
When to use the API
Reach for the API when:
- Your articles are authored elsewhere — in a Git repo, a CMS, a spreadsheet, another help center. You want a sync, not a copy-paste.
- You want articles versioned and reviewed in pull requests. Markdown in a Git repo gives you diff, branch, review, merge — the same review discipline as code.
- You’re migrating from another help center. A one-time bulk import via the API is faster than recreating articles in the UI.
- You’re building a content pipeline. Generate articles from product specs, sync from a spec repository, regenerate when source data changes.
If your team writes content in the in-app editor and that flow is working, you don’t need the API.
What the API can do
The v1 surface covers the operations a content pipeline needs:
- Articles — List, get, create, update, delete, publish, mark-reviewed
- Categories — List, get, create, update, delete
- Subcategories — List, create, update, delete
- Sections — List, get, create, update, delete
- Roles — List, get, create, update, delete
- Tags — List, create, update, delete
- Surveys — List, get, create, update, delete
- Templates — List, create, update, delete
- Knowledge bases — List, create, update, delete (delete requires
confirmName) - Translations — Correct a translation with a single call
- Search — Run a keyword query against article titles, content, summaries and keywords
- Settings — Read and update portal settings, including custom CSS,
templateConfigandlayoutConfigV3
The endpoints accept JSON. Articles can be created or updated with full content, summaries, keywords, custom metadata (uxPath, videoUrl, etc.), and category assignments.
Public article listings include categorySlug and publicUrl for each article. publicUrl respects your custom Knowledge Base domain when one is configured; otherwise, it falls back to the Atender /knowledge/<tenant>/<category>/<article> path.
What the API can’t do (yet)
Most of what used to require the in-app editor is now on the v1 surface:
- Roles and sections — you can create, update and delete both through the API.
roleIdson article create/update still accepts role UUIDs or role slugs. - Templates and surveys — full create, read, update and delete.
- Knowledge bases — you can create and delete them. Deleting a knowledge base requires
confirmNamein the request, so a stray call can’t remove one by accident. - Translations — a single call corrects a translation. Translations sync automatically every 15 minutes; to start a sync now, call
POST /api/v1/kb/translations/sync. - Layout and templates in settings —
templateConfigandlayoutConfigV3are read and written through the settings endpoint described below. - Images — base64 image upload tools let you add images without leaving your pipeline.
Still outside the KB article endpoints:
- Handbook procedures — Handbook is exposed through its own supported
/api/v1/handbook*endpoints for procedures, categories, and access rules. KB article endpoints remain under/api/v1/kb/*. If a tenant has multiple Handbooks, callers must pass and use the correct handbook partition for the procedures they are managing.
Updating portal settings and custom CSS
Portal settings can be read via GET /api/v1/kb/settings and updated via PUT /api/v1/kb/settings. Updating them requires a key with the knowledge:write scope.
Settings include customCss, a stylesheet of up to 20 KB that is scoped to your site, and a customCssEnabled switch that turns the stylesheet on or off without deleting it. A bad sheet returns 400 with a line and column for each problem, and selectors that are likely to break over time come back as meta.customCssWarnings.
Authentication
Every v1 KB call is authenticated with a tenant API key. Generate one in Settings → API & MCP:
- Click Create Key.
- Pick scopes:
knowledge:read(for read-only access) and/orknowledge:write(for create/update/delete). - Optionally set an end date if the key should stop working automatically.
- Name the key something obvious — “doc-as-code pipeline”, “migration script”, “github-actions-sync”.
- Click Create key. Copy the key — it’s shown once, then hidden.
- Set it as
Authorization: Bearer <key>on each request.
API keys come in two prefixes:
sa_live_*— Production keys. Make real changes to the live KB.sa_test_*— Sandbox keys. For development and testing.
API keys work until you revoke them, unless you set an end date. When a key reaches its end date, it stops authenticating, but the rest of the workspace keeps running. Settings → API & MCP shows each key’s stop date under the key name. Rotate or revoke keys there when team members leave or you suspect compromise.
The shape of an article
An article in the API has these fields:
{
"title": "How to update your payment method",
"slug": "update-payment-method",
"summary": "Open your account settings, go to Billing, click Change.",
"content": "...full markdown body...",
"categoryId": "cat_abc123",
"subcategoryId": null,
"status": "published",
"difficulty": "beginner",
"estimatedMinutes": 2,
"keywords": ["payment", "credit card", "billing"],
"customMetadata": {
"uxPath": "Account → Billing → Payment methods"
}
}
The customMetadata field is an open jsonb bucket — you can stash any structured data your downstream consumers need. Atender’s own pipeline puts uxPath, type, related[], and sourcePath here. The public read API exposes customMetadata so the Agent Stack and other downstream consumers can read it.
How idempotency works
You can send slug on both create and update. If the slug you send clashes with a live article, the API returns 409 instead of creating a duplicate, which makes re-running a pipeline safe: a repeated create fails cleanly rather than leaving you with two copies.
If you don’t send a slug, it is derived from the title, and when that slug is already taken the new article gets a numeric suffix — update-payment-method-2, then -3, and so on. Sending the same article twice without a slug therefore leaves you with two, so send an explicit slug in pipelines.
tags accepts tag ids or tag slugs. A tag that doesn’t exist returns 400, so create tags first.
The v1 endpoints do not upsert, so a pipeline that re-runs still has to do the “is this a create or an update?” branching itself: look the article up with GET /api/v1/kb/articles/by-slug/{slug} and PATCH /api/v1/kb/articles/{id} when it already exists.
Categories (slug from name), subcategories (slug scoped to categoryId) and tags get a numeric suffix starting at -1 when their slug is already taken. POST /api/v1/kb/categories and POST /api/v1/kb/tags also accept an optional kbId; when you omit it, Atender uses the default Knowledge Base, and when you pass an ID from another tenant the API returns 400. Category and tag slug uniqueness is scoped per Knowledge Base, so multi-brand pipelines should pass kbId before doing their own create/update branching.
Rate limits
The API has standard rate limits — generous for normal use, reasonable for bulk imports. If you’re bulk-importing a few thousand articles, expect to add backoff between calls. The error response includes a Retry-After header when limits are hit.
A doc-as-code pattern
The pattern Atender’s own help center uses:
- Articles are markdown files in a Git repo, with frontmatter for metadata.
- A small Python script reads each file, calls
/api/v1/kb/categoriesto ensure the category exists, then creates the article withPOST /api/v1/kb/articles— orPATCHes the existing one when the slug is already taken. - Embeddings rebuild server-side when the article is created or its content changes.
- Translations sync automatically every 15 minutes; a pipeline that needs them sooner can call
POST /api/v1/kb/translations/sync.
If that’s the shape you want, see Push articles via API for a working example.
Where to go next
- Push your first article via API: Push articles via API
- Generate an API key: API keys
- Understand what gets retrieved: KB search and AI retrieval