Skip to main content
An article is one unit of knowledge: a title, a slug, a body of markdown, and metadata describing where it lives in your knowledge base and who can see it. Every article belongs to a knowledge base. Published articles are embedded into a vector index that your chatbots and search endpoints pull from.

Anatomy

{
  "object": "article",
  "id": "8f3a9d2e-1b4c-4f5d-9e8a-7c3b2a1d0f9e",
  "knowledge_base_id": "2c1b4a9f-7e8d-4a3c-9b1f-6e5d4c3b2a1f",
  "category_id": "5d694e14-5440-4f5d-9e8a-7c3b2a1d0f9e",
  "title": "Returns & refunds",
  "slug": "returns-and-refunds",
  "content": "## Our policy\n\nReturns are accepted within 30 days...",
  "content_plain": "Our policy Returns are accepted within 30 days...",
  "status": "published",
  "visibility": "public",
  "language": "en",
  "indexing_status": "indexed",
  "indexed_at": "2026-05-22T14:02:11+00:00",
  "published_at": "2026-05-22T14:01:58+00:00",
  "created_at": "2026-05-22T13:59:01+00:00",
  "updated_at": "2026-05-22T14:01:58+00:00"
}

Where articles live

Articles sit inside a two-tier container:

Knowledge base

Top-level scope. One org can host many knowledge bases. Set with knowledge_base_idrequired on every article, and it must belong to your organization. See Knowledge Bases.

Category

A tree of folders inside a knowledge base. category_id is the leaf the article belongs to; categories themselves nest via parent_id. null for articles at the KB root. The category must belong to your organization. See Article Categories.

Send markdown — we derive the rest

Every article has two parallel bodies:
  • content is the source — your markdown, edited by humans, rendered to readers. This is the only body you write.
  • content_plain is a plain-text mirror the server derives from content and uses for search, embeddings, previews, and snippets.
The derivation runs on every create and every PATCH that includes content. It renders the markdown to HTML, strips tags, keeps <img alt> copy inline, and collapses whitespace — the same projection the dashboard editor produces, so what’s indexed via the API matches what’s indexed via the UI.
Don’t try to send content_plain in the request body — the field isn’t accepted as input. The response includes it so you can verify what got indexed.

Image re-hosting

Articles created or updated through the API have every external image in content pulled into Awardee’s asset library — the same store the dashboard editor uses. This runs synchronously during the write, so the response body always reflects the canonical post-write state. Each image — whether you sent markdown ![alt](url) or an HTML <img src="url"> — is replaced with an asset reference tag carrying the library asset’s id, not a URL:

What you send

![Returns portal](https://example.com/image.png)

What `content` stores

<img data-asset-id="2c1b4a9f-7e8d-4a3c-9b1f-6e5d4c3b2a1f" alt="Returns portal">
The live URL is resolved from the asset id at read time (public viewer, chatbot, embeds), so changing an image’s visibility or migrating buckets never breaks a stored article. If you send an image without alt text, the attribute is omitted and a concise caption is filled in automatically (see below).

Dedup

Images are content-hashed, so re-using the same picture across articles stores one asset and one set of bytes.

Smart alt text & vision

Every rehosted image is queued for AI enrichment: a concise alt caption plus a rich, searchable description that’s folded into the article’s embeddings so the chatbot can reason about what each image shows. This happens asynchronously — the asset exists immediately; its caption and description populate shortly after.
URLs already pointing at Awardee storage are left untouched. Re-PATCHing the same body is idempotent — once an image is an asset reference it carries no external URL, so there’s nothing left to fetch. Failed fetches (broken source, timeout) keep the original URL in place — the rest of the save still succeeds. Images on internal articles land in the private bucket; public and chatbot_only articles use the public bucket. The cap per image is 15 MiB.

Publish lifecycle

Status transitions trigger server-side work:
TransitionWhat fires
publishedArticle enters the indexing pipeline; embeddings computed; article.published webhook
unpublished or archived (from published)Embeddings removed; article.unpublished webhook
Any changearticle.updated webhook
Indexing completesarticle.indexed webhook
Indexing failsarticle.indexing_failed webhook
Polling for indexing_status === "indexed" is the supported signal that an article is searchable — but for non-interactive flows, subscribe to article.indexed instead. See Publishing & indexing.

Visibility

public

Surfaced on your public knowledge base site and to anonymous chatbot visitors.

internal

Hidden from public surfaces. Indexed for authenticated agents only.

chatbot_only

Not rendered in the KB UI. Available to chatbots as a retrieval source.

Translations, versions, and relations

Satellite resources hang off every article.

Translations

Per-language copies of title + content. The primary article’s language is the canonical one; translations cover everything else and index alongside the primary.

Versions

Snapshots of content. Auto-created on every PATCH that changes title or content, plus manual snapshots via POST /articles/{id}/versions. Restore with POST /articles/{id}/versions/{version}/restore.

Related articles

Cross-links between articles in the same org. Manage them under /articles/{id}/relations — list, add one, bulk replace/add, or remove one.

Common workflows

Sync a Notion, Contentful, or in-house CMS into Awardee on a schedule. Use Idempotency-Key on the create so retries don’t duplicate, and PATCH on every subsequent run.
  1. For each source article, compute a stable key like cms-<source-id>.
  2. POST /articles with Idempotency-Key: cms-<source-id> and status: "draft".
  3. Later runs PATCH /articles/{id} with the updated content — auto-snapshots the prior version for you.
  4. Flip status to "published" when ready — indexing fires automatically.

Webhook events

Subscribe in Dashboard → Webhooks. Article-related events:
EventWhen it fires
article.createdA new article row is written
article.updatedAny field changes
article.deletedThe article row is removed
article.publishedStatus transitions to published; indexing kicked off
article.unpublishedStatus leaves published for unpublished or archived
article.indexedEmbedding pipeline finished successfully
article.indexing_failedEmbedding pipeline errored out
article_category.createdNew category created
article_category.updatedCategory fields change
article_category.deletedCategory removed
Payloads use the webhook serializers in Webhook events.