---
title: "Create an article (draft) from a pre-built outline"
method: POST
path: "/v3/cms/articles"
tags: ["CMS"]
---

# Create an article (draft) from a pre-built outline

`POST /v3/cms/articles`

Create a draft article. This does NOT generate the body content. For a fully AI-written article, prefer `generate_article` (which produces the outline and the content in one step). Use this only when you already have an outline from `generate_outline` and want manual control: pass that outline under `articleOutline` (see its description), then call `start_article_generation` with the returned `slug` to write the content.

## Request body

- object
  - `teamId` string — Team id (falls back to the session's active project).
  - `title` string, required — Article title.
  - `content` string — Optional markdown body. Leave empty for a draft you will fill via start_article_generation.
  - `type` string — Article type: listicle | guide | comparison | review | news (or blog for a generic post). Must match the outline's structure.
  - `status` string
  - `contentArticleType` string, nullable — "pillar" or "cluster" for pillar/cluster content, null/omitted for generic posts.
  - `authorName` string
  - `topicId` string, required — Required. Id of the team's topic cluster this article belongs to — get it from `topic_clusters_list`, or create one with `create_topic_cluster`. The topic name is taken from this cluster (do not pass a free-text topic).
  - `keywords` object[]
    - `keyword` string, required
    - `type` 'primary' | 'secondary', required
  - `prompts` object[]
    - `prompt` string, required
    - `type` 'primary' | 'secondary', required
  - `metaData` object
    - `metaDescription` string
    - `metaTitle` string
    - `ogTitle` string
    - `ogDescription` string
    - `twitterTitle` string
    - `twitterDescription` string
    - `canonicalUrl` string
  - `articleOutline` object — Outline wrapper consumed by the generator. Shape: { generateOutlineResponse: <the FULL object returned by generate_outline>, outlineAdditionalElements: { targetWordCount:number, _shouldIncludeFAQ:boolean, _shouldIncludeTldr:boolean, _shouldIncludeConclusion:boolean, _shouldIncludeCTA:boolean }, outlineNonEditable: { introduction: { estimated_words:150 }, conclusion?: { estimated_words:150 } }, audience_level:'auto', content_tone?:string }. Do NOT hand-author the outline — obtain it from generate_outline and pass it through unchanged.
  - `internalLinkTargetSlugs` string[] — Slugs of existing SnowSEO articles to link out to (internal links).
  - `internalLinkTargetUrls` string[] — Absolute http(s) URLs to link out to that are not SnowSEO articles.
  - `language` string — Language code to write this article in (e.g. 'es'). Usually two letters; Chinese is 'zh_CN'/'zh_TW' and Hebrew is 'iw'. Defaults to the brand's Writing Language, then its brand language. Only pass this when the user asks for a specific language for this one article.

## Response `201`

Default Response

- object
  - `article` object
    - `slug` string
    - `teamId` string
    - `title` string
    - `status` string
    - `type` string

## Other responses

- `400` — Default Response
- `500` — Default Response

---

[API](https://skmtc.net/snowseo/apis/snowseo-api.md) · [All operations](https://skmtc.net/snowseo/apis/snowseo-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/snowseo/snowseo-api/versions/aa8eaa9e34a0/schema)
