Doc-as-code with the KB API
Doc-as-code is the pattern of treating help-center articles like application code — authored as files in a version-controlled repository, reviewed in pull requests, and synced into the live KB by an automated pipeline. Atender is built to support this pattern via /api/v1/kb/* and a tenant API key.
It is the pattern this very help center uses. The articles you’re reading live as markdown files in a Git-tracked vault, and a small Python script reads them and upserts to the KB whenever the source files change.
Why doc-as-code
Some help centers fit the in-app editor perfectly — small team, low volume, content authored by the same people who deliver support. For those teams, the in-app editor is exactly right.
The case for doc-as-code is stronger when:
- Multiple authors need to review each other’s changes. A pull request is a much better review surface than “tell me when you’re done and I’ll look at the article in the editor.”
- The source of truth lives elsewhere. If your engineering team writes specs in Markdown and your support team wants those specs translated into customer-facing articles, syncing from one repo to the KB closes the loop automatically.
- You want a version history beyond Atender. Git keeps every revision, with author attribution, in your own repo. The in-app editor doesn’t keep an external history.
- You’re migrating from another help center. A bulk import via the API is dramatically faster than recreating articles in the UI.
- You want CI to validate articles. Spell checkers, link checkers, frontmatter linters — all easy to run on Markdown files in CI, hard to bolt onto a hosted editor.
If none of those apply, stay in the in-app editor. Doc-as-code is overhead that only pays off when one of those needs is real.
The architecture
A doc-as-code setup has three parts:
- Source of truth — Git repo (or any version-controlled folder) — Markdown files with frontmatter for metadata
- Push script — The same repo or your CI — Reads the files, calls the API to upsert
- Live KB — Atender — The rendered, searchable, AI-retrievable surface
The push script is the bridge. It walks the repo, calls /api/v1/kb/categories to ensure each category exists, then calls /api/v1/kb/articles to upsert each article. It runs on every commit (in CI) or on demand (locally).
That default flow is enough when you’re syncing into the tenant’s default KB. If you sync a second brand, region, or other partition into a separate knowledge base, make the target explicit: include kbId when creating categories or tags, and include kbId on category imports. That keeps shared names like “Getting started” or “Billing” from landing in the wrong KB.
For what the script must handle — idempotent upserts, the frontmatter contract, and the requirements checklist — see Build an idempotent KB push script. For what the API does and doesn’t sync after a push (embeddings, translations, roles, sections), see KB API sync behavior and limits.
A real example: this very help center
The Atender help center is doc-as-code. The pattern in production:
- Articles live in
Atender/KB Articles/in an Obsidian vault on a maintainer’s machine. - A Python script reads each
.mdfile, parses the frontmatter, and walks every category. - The script calls
/api/v1/kb/*with a production API key stored in 1Password. - Categories upsert by name; articles upsert by slug.
- After the bulk push, the automatic translation sync, which runs every 15 minutes, refreshes non-English versions.
The whole loop — edit, save, push — takes under a minute for a single article and a few minutes for a whole batch. The KB stays current without anyone “remembering to update the help center.”