> ## Documentation Index
> Fetch the complete documentation index at: https://developers.octaviatech.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Content Management

> How the AI CMS content model fits together and the order to create things in.

Content in **AI CMS** is organised as a small dependency graph. Nothing in it can be
created in isolation, so the order matters. This page shows the shape of the model and
the order to build it in.

<Card title="Octavia AI CMS – Product Overview" icon="book-open" href="https://octaviatech.app/products/ai-cms" arrow="true">
  What AI CMS does and how it fits into your stack
</Card>

***

## The dependency graph

Most content hangs off an **article**, and an article needs three things to exist before
it: a **language**, an **author**, and a **category**. A **subcategory** belongs to a
category, so it comes just after.

```mermaid theme={null}
flowchart TD
    L["1. Language<br/><small>POST /languages/create</small>"]
    A["2. Author<br/><small>POST /authors/create</small>"]
    C["3. Category<br/><small>POST /categories/create</small>"]
    SC["4. Subcategory<br/><small>POST /subcategories/create</small>"]
    T["Tags<br/><small>POST /tags/create</small>"]
    ART["5. Article<br/><small>POST /articles/create</small>"]
    F["Forms<br/><small>POST /forms/create</small>"]

    L --> ART
    A --> ART
    C --> ART
    C --> SC
    SC --> ART
    T --> ART
    F --> SUB
    SUB["Submissions<br/><small>POST /forms/submit</small>"]
    ART --> SUB
```

Read it as: language, author and category are the three leaves every article depends
on. Subcategory hangs off category, tags hang off nothing, and forms are a separate
tree that submissions hang from.

***

## The order to create things in

Follow this sequence the first time you populate a tenant. Each step lists the minimum
fields the API actually requires.

<Steps>
  <Step title="1. Create a language">
    Languages are referenced by a two-letter code and are unique per tenant. An article
    can only be written in a language that exists.

    **Required:** <code>code</code>, <code>name</code>

    ```json theme={null}
    {
      "code": "en",
      "name": "English"
    }
    ```

    <Note>
      The <code>language</code> field on an article only accepts codes that exist here.
      Creating the language first is what makes that field work.
    </Note>
  </Step>

  <Step title="2. Create an author">
    An author is a public profile attached to articles. The email is used for
    attribution and must be unique.

    **Required:** <code>name</code>, <code>slug</code>, <code>email</code>

    ```json theme={null}
    {
      "name": "Nima Janbaz",
      "slug": "nima-janbaz",
      "email": "nima@octaviatech.app"
    }
    ```

    <Tip>
      If you omit <code>author</code> when creating an article, the API falls back to
      the authenticated user. Creating authors explicitly is still worth it — it lets
      you reassign bylines later.
    </Tip>
  </Step>

  <Step title="3. Create a category">
    Categories are the top level of the content tree. Slugs are URL-facing and must be
    unique.

    **Required:** <code>name</code>, <code>slug</code>

    ```json theme={null}
    {
      "name": "Engineering",
      "slug": "engineering",
      "description": "Technical writing and engineering notes"
    }
    ```
  </Step>

  <Step title="4. Create a subcategory">
    A subcategory always belongs to a category, so this step needs the category ID from
    step 3.

    **Required:** <code>name</code>, <code>categoryId</code>

    ```json theme={null}
    {
      "name": "TypeScript",
      "slug": "typescript",
      "categoryId": "{{categoryId}}"
    }
    ```

    <Note>
      A subcategory is optional. An article can be filed under a category alone — set
      <code>subCategory</code> to an empty array or omit it.
    </Note>
  </Step>

  <Step title="5. Create your tags">
    Tags are free-form and depend on nothing. Create them up front so you can attach
    them to every article as you go.

    ```json theme={null}
    {
      "name": "typescript"
    }
    ```
  </Step>

  <Step title="6. Create an article">
    Now the dependencies are satisfied. An article takes an array of category IDs and,
    optionally, an array of subcategory IDs.

    **Required:** <code>mainTitle</code>, <code>content</code>, <code>category</code>

    ```json theme={null}
    {
      "mainTitle": "Shipping the AI CMS SDK",
      "content": "Full article body...",
      "category": ["{{categoryId}}"],
      "subCategory": ["{{subcategoryId}}"],
      "author": "{{authorId}}",
      "language": "en",
      "tags": ["typescript", "sdk"],
      "slug": "shipping-the-ai-cms-sdk"
    }
    ```
  </Step>
</Steps>

***

## Reference: fields on each resource

Use this as a quick check when you are unsure which field is mandatory. Only
**required** fields block a request.

| **Resource**    | **Required**                       | **Optional**                                                                                                                                                           |
| --------------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Language**    | `code`, `name`                     | —                                                                                                                                                                      |
| **Author**      | `name`, `slug`, `email`            | `bio`, `avatar`, `isPrivate`, `isActive`                                                                                                                               |
| **Category**    | `name`, `slug`                     | `thumbnail`, `description`, `isPrivate`, `isActive`                                                                                                                    |
| **Subcategory** | `name`, `categoryId`               | `slug`, `description`, `icon`, `banner`, `order`, `isActive`                                                                                                           |
| **Article**     | `mainTitle`, `content`, `category` | `title2`, `title3`, `slug`, `summary`, `thumbnail`, `tags`, `subCategory`, `author`, `gallery`, `publishDate`, `isPublished`, `isPrivate`, `language`, `autoSummarize` |

<Note>
  `category` and `subCategory` on an article are **arrays of IDs**, not single strings.
  `author` is a single ID, or omit it to fall back to the authenticated user.
</Note>

***

## Forms live in their own tree

Forms do not depend on articles, categories or authors. They have their own section-based
schema, and submissions hang off a form. Because that is a separate model, forms are
documented under their own group.

<Card title="Forms" icon="list-todo" href="/api-reference/ai-cms/forms/introduction" arrow="true">
  The form model, submissions, and captcha
</Card>

***

## Tags are a flat namespace

Tags have no hierarchy and no parent. One endpoint creates them by name, and they are
referenced by name rather than ID when attached to an article:

```json theme={null}
{ "tags": ["typescript", "sdk", "api"] }
```

<Card title="Tags" icon="tags" href="/api-reference/ai-cms/tags/get-all" arrow="true">
  Create and search tags
</Card>

***

## Where to go next

<CardGroup cols={2}>
  <Card title="Articles" icon="file-text" href="/api-reference/ai-cms/articles/get-all" arrow="true">
    Read, search, and manage articles.
  </Card>

  <Card title="Content flow" icon="git-branch" href="/api-reference/ai-cms/quickstart" arrow="true">
    A runnable end-to-end example that builds the whole graph.
  </Card>
</CardGroup>
