# Octavia AI CMS > Headless, multilingual content API with AI automation, forms, and analytics. 132 operations across 11 resource groups, plus official SDKs for JavaScript, Python, PHP, C# and Go. Base URL: `https://api.octaviatech.app/cms` Docs: https://developers.octaviatech.app ## For AI agents This file is a map of the **AI CMS** API only. Two other artifacts are meant to be read directly by a coding agent, and are more useful than anything below if you are writing code: - Skill file — https://github.com/octaviatech/octavia-ai-cms/blob/main/.claude/skills/octavia-cms/SKILL.md Installable, versioned with the SDK, and written as rules rather than prose. It prevents the mistakes that produce code that compiles and then fails: the one required header, where pagination actually lives, the per-language result field names, the content-model dependency order, and the two SDK bugs below. - Agent guide — https://developers.octaviatech.app/api-reference/ai-cms/sdks/llm-agents How to install the skill, how to pick which file to load, and how to verify a change. - Example projects — https://github.com/octaviatech/octavia-ai-cms/tree/main/examples Eight runnable apps, one per stack, each using the SDK for its own language. ## Non-negotiables 1. **One header only: `x-api-key`.** It is mandatory on every operation. The gateway resolves the tenant, the user and the service status from the key and sets those headers itself. Never send `x-tenant-id`, `x-service-status`, `x-user-id` or `Authorization`. No SDK accepts them. 2. **Every response is the same envelope** — `{ success, statusCode, message, data }`, all four always present, on success and on failure. No endpoint returns a bare array or a bare error. 3. **`pagination` lives inside `data`**, next to the row array, not beside `data`: `data: { articleListItem: [...], pagination: { total, page, limit, totalPages } }`. The row key is per-resource — `articleListItem` for articles, `formListItem` for forms, `author`, `category`, `subCategory`, `language`, `tag`, `comments`, `items`. 4. **Prefer the official SDK** for the language you are writing in. Fall back to raw HTTP only when an endpoint is genuinely missing, and still send just `x-api-key`. ## Install the SDK ``` npm install @octaviatech/cms pip install octavia-cms-sdk composer require octavia/cms dotnet add package Octavia.CmsSDK go get github.com/octaviatech/octavia-ai-cms/packages/sdk-go ``` ## Common first errors | Code | Meaning | | ----- | -------------------------------------------------------------- | | 401 | `x-api-key` missing or invalid | | 403 | Key is valid, but its role lacks the permission | | 422 | A required field is missing, or a value failed validation | | 423 | The workspace is inactive, usually an expired plan | | 426 | The tenant's seat limit for this resource is reached | | 429 | Rate limited — no SDK retries, so back off yourself | ## Content model order An article cannot be created until its dependencies exist: `language.create` → `author.create` → `category.create` → `subcategory.create` (optional, needs a `categoryId`) → `article.create`. `/articles/create` requires `mainTitle`, `content` and `category`, and its body is closed, so an unknown key is a 422 rather than a silent drop. `category` and `subCategory` are arrays of ids. ## Endpoint map 132 operations, grouped as in the documentation sidebar. The OpenAPI spec is the authoritative source for request and response schemas. ### Get started - Introduction — /api-reference/ai-cms/introduction - Quickstart — /api-reference/ai-cms/quickstart - Base URL — /api-reference/ai-cms/base-url - API keys — /api-reference/ai-cms/apikeys - Authentication — /api-reference/ai-cms/authentication - Response format — /api-reference/ai-cms/response-fromat - Status codes — /api-reference/ai-cms/status-codes - Rate limits and errors — /api-reference/ai-cms/rate-limits-and-errors - Plans — /api-reference/ai-cms/plans ### How to use - SDKs overview — /api-reference/ai-cms/sdks/overview - Example projects — /api-reference/ai-cms/examples - Agent skill — /api-reference/ai-cms/sdks/skill - Using these files — /api-reference/ai-cms/sdks/llm-agents ### SDKs - JavaScript — /api-reference/ai-cms/sdks/javascript - Python — /api-reference/ai-cms/sdks/python - PHP — /api-reference/ai-cms/sdks/php - C# — /api-reference/ai-cms/sdks/csharp - Go — /api-reference/ai-cms/sdks/go ### Languages (5) `/languages/getAll` · `/languages/getById` · `/languages/create` · `/languages/update` · `/languages/delete` - Languages overview — /api-reference/ai-cms/languages/get-all ### Articles (29) - `GET /articles/getAll` - `GET /articles/search` - `GET /articles/advanceSearch` - `GET /articles/getById/{id}` - `GET /articles/getBySlug/{slug}` - `GET /articles/getByCategoryId/{categoryId}` - `GET /articles/getByCategorySlug/{slug}` - `GET /articles/getBySubCategoryId/{subCategoryId}` - `GET /articles/getBySubCategorySlug/{slug}` - `GET /articles/getByAuthorId/{authorId}` - `GET /articles/getByTag/{tag}` - `POST /articles/create` - `PUT /articles/update` - `PUT /articles/archive` — soft delete, not a publish and not a remove - `DELETE /articles/delete/{id}` — the actual remove - `GET /articles/seoAnalysis/{id}` - `GET/PUT /articles/engagementSettings` There is no publish endpoint: publishing is a field update that sets `isPublished`. - Articles overview — /api-reference/ai-cms/content-management/introduction - Get all — /api-reference/ai-cms/articles/get-all - Create — /api-reference/ai-cms/articles/create - Update — /api-reference/ai-cms/articles/update - Archive — /api-reference/ai-cms/articles/archive ### Comments and reactions (12) `GET /articles/{id}/comments` · `POST /articles/{id}/comments` · `GET /articles/comments/getAll` · `PATCH /articles/comments/{commentId}` · `DELETE /articles/comments/{commentId}` · `POST|DELETE /articles/{id}/reaction` · `GET /articles/{id}/reactionSummary` · `POST|DELETE /articles/comments/{commentId}/reaction` · `GET /articles/comments/{commentId}/reactionSummary` - Comments and reactions — /api-reference/ai-cms/articles/get-comments ### Categories (6) `/categories/getAll` · `/categories/getById/{id}` · `/categories/getBySlug/{slug}` · `/categories/create` · `/categories/update` · `/categories/delete` ### Subcategories (7) `/subcategories/getAll` · `/subcategories/getByCategoryId/{categoryId}` · `/subcategories/getById/{id}` · `/subcategories/getBySlug/{slug}` · `/subcategories/create` · `/subcategories/update` · `/subcategories/delete` ### Authors (6) `/authors/getAll` · `/authors/getById/{id}` · `/authors/getBySlug/{slug}` · `/authors/create` · `/authors/update` · `/authors/delete` ### Tags (3) `GET /tags/getAll` · `GET /tags/search` · `POST /tags/create` ### Forms (10) `/forms/getAll` · `/forms/getById/{id}` · `/forms/getBySlug/{slug}` · `/forms/getNextById/{id}` · `/forms/create` · `/forms/update` · `/forms/delete` · `POST /forms/{id}/submit` · `POST /forms/{id}/internal-submit` · `/forms/captcha/config` `forms/getAll` returns only a submissions count per form — no id, title or slug — so it cannot drive a form picker. Use `forms/getById/{id}`. - Forms overview — /api-reference/ai-cms/forms/introduction - Submit — /api-reference/ai-cms/forms/submit ### Form submissions (12) `/forms/{id}/getAllSubmissions` · `/forms/submissions/getAll` · `/forms/getSubmissionById/{id}` · `/forms/submission/update/{id}` · `/forms/submission/delete/{id}` · `/forms/submission/{id}/relations` and its `connect`, `disconnect` and `reorder` variants · `/forms/submissions/relations/backfill` ### AI (26) Text tools: `/ai/summarize` · `/ai/translate` · `/ai/translateArticle` · `/ai/translateForm` · `/ai/seoOptimize`, each with a `/stream` variant where one exists. Article operations: `/ai/generateTitle` · `/ai/generateContent` · `/ai/optimizeArticle` · `/ai/generateImage`. Social publishing: `/ai/repurpose` · `/ai/repurpose/template` · `/ai/social/connections` · `/ai/social/{linkedin,twitter,telegram}/connect` · `/ai/social/{linkedin,twitter,telegram}/publish`. - AI overview — /api-reference/ai-cms/ai/summarize - Summarize — /api-reference/ai-cms/ai/summarize - Translate — /api-reference/ai-cms/ai/translate ### AI conversation (6) `/ai/conversation/start` · `/ai/conversation/continue` · `/ai/conversation/generate` · `/ai/conversation/generate/stream` · `/ai/conversation/regenerate` · `/ai/conversation/{conversationId}` - Start a conversation — /api-reference/ai-cms/ai-conversation/start ### Reports and analytics (22) `/reports/getStatistics` · `/reports/contentOverview` · `/reports/contentHealth` · `/reports/categoryPerformance` · `/reports/publishingPerformance` · `/reports/topArticles` · `/reports/periodComparison` · `/reports/aiContentImpact` · `/reports/aiUsageBreakdown` · `/reports/commentOverview` · `/reports/formsOverview` · `/reports/submissionsOverview` · `/reports/dashboardConfig` · `/reports/chart/{contentTrend,engagementTrend,submissionFunnel}` · `/reports/getTenantStatistics/{tenantId}` · `/reports/getUserStatistics/{userId}` · `/reports/getAuthorStatistics/{authorId}` · `/reports/getAllUsersStatistics` · `/reports/getAllAuthorsStatistics` Reports read from the tenant the key belongs to. Do not pass a tenant id yourself. - Reports — /api-reference/ai-cms/reports/get-statistics