> ## 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.

# Quickstart

> Build a working content graph against the AI CMS API in five minutes.

This walks through the whole content model end to end: create a language, an author, a
category, and finally an article — then read it back. It assumes you already have an
API key.

<Info>
  New here? Start with [Authentication](/api-reference/ai-cms/authentication)
  and [API keys](/api-reference/ai-cms/apikeys). The
  [SDKs](/api-reference/ai-cms/sdks/overview) do all of this for you in any
  supported language.
</Info>

***

## Before you start

Set two variables. Everything below uses them.

```bash theme={null}
export CMS_BASE="https://api.octaviatech.app/cms"
export CMS_KEY="your-api-key"
```

A tiny helper makes the rest readable:

```bash theme={null}
cms() {
  curl -s -X "$CMS_BASE$1" \
    -H "x-api-key: $CMS_KEY" \
    -H "Content-Type: application/json" \
    ${2:+-d "$2"}
}
```

***

<Steps>
  <Step title="1. Create a language">
    Articles can only be written in a language that already exists.

    ```bash theme={null}
    cms /languages/create '{"code":"en","name":"English"}'
    ```

    ```json theme={null}
    { "success": true, "statusCode": 201, "message": "Language created successfully", "data": { "code": "en", "name": "English" } }
    ```
  </Step>

  <Step title="2. Create an author">
    ```bash theme={null}
    cms /authors/create '{"name":"Nima Janbaz","slug":"nima-janbaz","email":"nima@octaviatech.app"}'
    ```

    Keep the returned `_id` — the article needs it.
  </Step>

  <Step title="3. Create a category">
    ```bash theme={null}
    cms /categories/create '{"name":"Engineering","slug":"engineering"}'
    ```

    Keep this `_id` too. A subcategory cannot be created without it.
  </Step>

  <Step title="4. Create a subcategory">
    ```bash theme={null}
    cms /subcategories/create '{"name":"TypeScript","slug":"typescript","categoryId":"<category-id>"}'
    ```

    <Note>
      Optional. Skip it if you file articles under categories only.
    </Note>
  </Step>

  <Step title="5. Create an article">
    ```bash theme={null}
    cms /articles/create '{
      "mainTitle": "Shipping the AI CMS SDK",
      "content": "Full article body...",
      "category": ["<category-id>"],
      "subCategory": ["<subcategory-id>"],
      "author": "<author-id>",
      "language": "en",
      "tags": ["typescript", "sdk"]
    }'
    ```

    <Warning>
      <code>category</code> and <code>subCategory</code> are arrays of IDs. A single
      string is rejected.
    </Warning>
  </Step>

  <Step title="6. Read it back">
    ```bash theme={null}
    cms '/articles/getAll?page=1&limit=10'
    ```

    ```json theme={null}
    {
      "success": true,
      "statusCode": 200,
      "message": "Request successful",
      "data": { "articles": [ { "_id": "…", "mainTitle": "Shipping the AI CMS SDK" } ] },
      "pagination": { "total": 1, "page": 1, "limit": 10, "totalPages": 1 }
    }
    ```
  </Step>
</Steps>

***

## Adding a form

Forms are a separate tree and can be built at any time. Create one, then submit to it:

```bash theme={null}
cms /forms/create '{
  "title": { "en": "Contact us" },
  "slug": "contact-us",
  "sections": [
    {
      "title": { "en": "Your details" },
      "fields": [
        { "name": "email", "type": "email", "label": { "en": "Email" }, "required": true }
      ]
    }
  ]
}'

cms '/forms/<form-id>/submit' '{"language":"en","values":{"email":"nima@octaviatech.app"}}'
```

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

***

## Using an SDK instead

The same sequence, in JavaScript, with no HTTP plumbing:

```ts theme={null}
import { CMS } from "@octaviatech/cms";

const cms = CMS.init(process.env.OCTAVIA_API_KEY!);

await cms.language.create({ code: "en", name: "English" });
const author = await cms.author.create({
  name: "Nima Janbaz",
  slug: "nima-janbaz",
  email: "nima@octaviatech.app",
});
const category = await cms.category.create({
  name: "Engineering",
  slug: "engineering",
});

await cms.article.create({
  mainTitle: "Shipping the AI CMS SDK",
  content: "Full article body...",
  category: [category.data._id],
  author: author.data._id,
  language: "en",
});
```

<CardGroup cols={2}>
  <Card title="JavaScript" icon="js" href="/api-reference/ai-cms/sdks/javascript" arrow="true">
    Node.js and browser.
  </Card>

  <Card title="Python" icon="file" href="/api-reference/ai-cms/sdks/python" arrow="true">
    Python 3.9+.
  </Card>

  <Card title="PHP" icon="php" href="/api-reference/ai-cms/sdks/php" arrow="true">
    PHP 8.0+.
  </Card>

  <Card title="C#" icon="circle-dashed" href="/api-reference/ai-cms/sdks/csharp" arrow="true">
    .NET 6+.
  </Card>

  <Card title="Go" icon="package" href="/api-reference/ai-cms/sdks/go" arrow="true">
    Go 1.21+.
  </Card>
</CardGroup>

***

## Common first errors

| **Code** | **What it means**                                                                                                      |
| -------- | ---------------------------------------------------------------------------------------------------------------------- |
| **401**  | The `x-api-key` header is missing or the key is invalid. Check [Authentication](/api-reference/ai-cms/authentication). |
| **403**  | The key is valid but its role cannot do this. See [API keys](/api-reference/ai-cms/apikeys).                           |
| **422**  | A required field is missing, or a value failed the field's validation.                                                 |
| **423**  | The workspace is inactive — usually an expired plan. Check the dashboard.                                              |
| **429**  | Over 50 requests per second. Back off and retry.                                                                       |

<Note>
  Every response is wrapped in the same envelope, so you can branch on
  <code>statusCode</code> or <code>success</code> without parsing the body. See
  [Response format](/api-reference/ai-cms/response-fromat).
</Note>
