curl --request POST \
--url https://api.snowseo.com/v3/generate-article/create-and-start \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"topicId": "<string>",
"teamId": "<string>",
"primaryKeywords": [
"<string>"
],
"secondaryKeywords": [
"<string>"
],
"promptInsights": [
"<string>"
],
"competitorUrls": [
"<string>"
],
"tone": "<string>",
"customInstructions": "<string>",
"customInstructionsUseWithBrand": true,
"internalLinkTargetSlugs": [
"<string>"
],
"internalLinkTargetUrls": [
"<string>"
],
"includeTldr": true,
"includeFaq": true,
"includeConclusion": true,
"includeCta": true,
"startGeneration": true,
"language": "<string>"
}
'import requests
url = "https://api.snowseo.com/v3/generate-article/create-and-start"
payload = {
"title": "<string>",
"topicId": "<string>",
"teamId": "<string>",
"primaryKeywords": ["<string>"],
"secondaryKeywords": ["<string>"],
"promptInsights": ["<string>"],
"competitorUrls": ["<string>"],
"tone": "<string>",
"customInstructions": "<string>",
"customInstructionsUseWithBrand": True,
"internalLinkTargetSlugs": ["<string>"],
"internalLinkTargetUrls": ["<string>"],
"includeTldr": True,
"includeFaq": True,
"includeConclusion": True,
"includeCta": True,
"startGeneration": True,
"language": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
topicId: '<string>',
teamId: '<string>',
primaryKeywords: ['<string>'],
secondaryKeywords: ['<string>'],
promptInsights: ['<string>'],
competitorUrls: ['<string>'],
tone: '<string>',
customInstructions: '<string>',
customInstructionsUseWithBrand: true,
internalLinkTargetSlugs: ['<string>'],
internalLinkTargetUrls: ['<string>'],
includeTldr: true,
includeFaq: true,
includeConclusion: true,
includeCta: true,
startGeneration: true,
language: '<string>'
})
};
fetch('https://api.snowseo.com/v3/generate-article/create-and-start', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.snowseo.com/v3/generate-article/create-and-start",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'topicId' => '<string>',
'teamId' => '<string>',
'primaryKeywords' => [
'<string>'
],
'secondaryKeywords' => [
'<string>'
],
'promptInsights' => [
'<string>'
],
'competitorUrls' => [
'<string>'
],
'tone' => '<string>',
'customInstructions' => '<string>',
'customInstructionsUseWithBrand' => true,
'internalLinkTargetSlugs' => [
'<string>'
],
'internalLinkTargetUrls' => [
'<string>'
],
'includeTldr' => true,
'includeFaq' => true,
'includeConclusion' => true,
'includeCta' => true,
'startGeneration' => true,
'language' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/generate-article/create-and-start"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"topicId\": \"<string>\",\n \"teamId\": \"<string>\",\n \"primaryKeywords\": [\n \"<string>\"\n ],\n \"secondaryKeywords\": [\n \"<string>\"\n ],\n \"promptInsights\": [\n \"<string>\"\n ],\n \"competitorUrls\": [\n \"<string>\"\n ],\n \"tone\": \"<string>\",\n \"customInstructions\": \"<string>\",\n \"customInstructionsUseWithBrand\": true,\n \"internalLinkTargetSlugs\": [\n \"<string>\"\n ],\n \"internalLinkTargetUrls\": [\n \"<string>\"\n ],\n \"includeTldr\": true,\n \"includeFaq\": true,\n \"includeConclusion\": true,\n \"includeCta\": true,\n \"startGeneration\": true,\n \"language\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.snowseo.com/v3/generate-article/create-and-start")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"topicId\": \"<string>\",\n \"teamId\": \"<string>\",\n \"primaryKeywords\": [\n \"<string>\"\n ],\n \"secondaryKeywords\": [\n \"<string>\"\n ],\n \"promptInsights\": [\n \"<string>\"\n ],\n \"competitorUrls\": [\n \"<string>\"\n ],\n \"tone\": \"<string>\",\n \"customInstructions\": \"<string>\",\n \"customInstructionsUseWithBrand\": true,\n \"internalLinkTargetSlugs\": [\n \"<string>\"\n ],\n \"internalLinkTargetUrls\": [\n \"<string>\"\n ],\n \"includeTldr\": true,\n \"includeFaq\": true,\n \"includeConclusion\": true,\n \"includeCta\": true,\n \"startGeneration\": true,\n \"language\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/generate-article/create-and-start")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"topicId\": \"<string>\",\n \"teamId\": \"<string>\",\n \"primaryKeywords\": [\n \"<string>\"\n ],\n \"secondaryKeywords\": [\n \"<string>\"\n ],\n \"promptInsights\": [\n \"<string>\"\n ],\n \"competitorUrls\": [\n \"<string>\"\n ],\n \"tone\": \"<string>\",\n \"customInstructions\": \"<string>\",\n \"customInstructionsUseWithBrand\": true,\n \"internalLinkTargetSlugs\": [\n \"<string>\"\n ],\n \"internalLinkTargetUrls\": [\n \"<string>\"\n ],\n \"includeTldr\": true,\n \"includeFaq\": true,\n \"includeConclusion\": true,\n \"includeCta\": true,\n \"startGeneration\": true,\n \"language\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body"<string>"Generate Article
Create and generate a complete, SEO-optimized article in a single call.
curl --request POST \
--url https://api.snowseo.com/v3/generate-article/create-and-start \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"title": "<string>",
"topicId": "<string>",
"teamId": "<string>",
"primaryKeywords": [
"<string>"
],
"secondaryKeywords": [
"<string>"
],
"promptInsights": [
"<string>"
],
"competitorUrls": [
"<string>"
],
"tone": "<string>",
"customInstructions": "<string>",
"customInstructionsUseWithBrand": true,
"internalLinkTargetSlugs": [
"<string>"
],
"internalLinkTargetUrls": [
"<string>"
],
"includeTldr": true,
"includeFaq": true,
"includeConclusion": true,
"includeCta": true,
"startGeneration": true,
"language": "<string>"
}
'import requests
url = "https://api.snowseo.com/v3/generate-article/create-and-start"
payload = {
"title": "<string>",
"topicId": "<string>",
"teamId": "<string>",
"primaryKeywords": ["<string>"],
"secondaryKeywords": ["<string>"],
"promptInsights": ["<string>"],
"competitorUrls": ["<string>"],
"tone": "<string>",
"customInstructions": "<string>",
"customInstructionsUseWithBrand": True,
"internalLinkTargetSlugs": ["<string>"],
"internalLinkTargetUrls": ["<string>"],
"includeTldr": True,
"includeFaq": True,
"includeConclusion": True,
"includeCta": True,
"startGeneration": True,
"language": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
title: '<string>',
topicId: '<string>',
teamId: '<string>',
primaryKeywords: ['<string>'],
secondaryKeywords: ['<string>'],
promptInsights: ['<string>'],
competitorUrls: ['<string>'],
tone: '<string>',
customInstructions: '<string>',
customInstructionsUseWithBrand: true,
internalLinkTargetSlugs: ['<string>'],
internalLinkTargetUrls: ['<string>'],
includeTldr: true,
includeFaq: true,
includeConclusion: true,
includeCta: true,
startGeneration: true,
language: '<string>'
})
};
fetch('https://api.snowseo.com/v3/generate-article/create-and-start', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.snowseo.com/v3/generate-article/create-and-start",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'title' => '<string>',
'topicId' => '<string>',
'teamId' => '<string>',
'primaryKeywords' => [
'<string>'
],
'secondaryKeywords' => [
'<string>'
],
'promptInsights' => [
'<string>'
],
'competitorUrls' => [
'<string>'
],
'tone' => '<string>',
'customInstructions' => '<string>',
'customInstructionsUseWithBrand' => true,
'internalLinkTargetSlugs' => [
'<string>'
],
'internalLinkTargetUrls' => [
'<string>'
],
'includeTldr' => true,
'includeFaq' => true,
'includeConclusion' => true,
'includeCta' => true,
'startGeneration' => true,
'language' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.snowseo.com/v3/generate-article/create-and-start"
payload := strings.NewReader("{\n \"title\": \"<string>\",\n \"topicId\": \"<string>\",\n \"teamId\": \"<string>\",\n \"primaryKeywords\": [\n \"<string>\"\n ],\n \"secondaryKeywords\": [\n \"<string>\"\n ],\n \"promptInsights\": [\n \"<string>\"\n ],\n \"competitorUrls\": [\n \"<string>\"\n ],\n \"tone\": \"<string>\",\n \"customInstructions\": \"<string>\",\n \"customInstructionsUseWithBrand\": true,\n \"internalLinkTargetSlugs\": [\n \"<string>\"\n ],\n \"internalLinkTargetUrls\": [\n \"<string>\"\n ],\n \"includeTldr\": true,\n \"includeFaq\": true,\n \"includeConclusion\": true,\n \"includeCta\": true,\n \"startGeneration\": true,\n \"language\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.snowseo.com/v3/generate-article/create-and-start")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"title\": \"<string>\",\n \"topicId\": \"<string>\",\n \"teamId\": \"<string>\",\n \"primaryKeywords\": [\n \"<string>\"\n ],\n \"secondaryKeywords\": [\n \"<string>\"\n ],\n \"promptInsights\": [\n \"<string>\"\n ],\n \"competitorUrls\": [\n \"<string>\"\n ],\n \"tone\": \"<string>\",\n \"customInstructions\": \"<string>\",\n \"customInstructionsUseWithBrand\": true,\n \"internalLinkTargetSlugs\": [\n \"<string>\"\n ],\n \"internalLinkTargetUrls\": [\n \"<string>\"\n ],\n \"includeTldr\": true,\n \"includeFaq\": true,\n \"includeConclusion\": true,\n \"includeCta\": true,\n \"startGeneration\": true,\n \"language\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.snowseo.com/v3/generate-article/create-and-start")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"title\": \"<string>\",\n \"topicId\": \"<string>\",\n \"teamId\": \"<string>\",\n \"primaryKeywords\": [\n \"<string>\"\n ],\n \"secondaryKeywords\": [\n \"<string>\"\n ],\n \"promptInsights\": [\n \"<string>\"\n ],\n \"competitorUrls\": [\n \"<string>\"\n ],\n \"tone\": \"<string>\",\n \"customInstructions\": \"<string>\",\n \"customInstructionsUseWithBrand\": true,\n \"internalLinkTargetSlugs\": [\n \"<string>\"\n ],\n \"internalLinkTargetUrls\": [\n \"<string>\"\n ],\n \"includeTldr\": true,\n \"includeFaq\": true,\n \"includeConclusion\": true,\n \"includeCta\": true,\n \"startGeneration\": true,\n \"language\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body"<string>"slug immediately. Poll Generation Status with that slug. Once generating is false, check error and status before reading the article with Get Article.How it works
- Provide a
title, atopicId(the topic cluster the article belongs to), alengthtier, and optionally a tone orcustomInstructions. - The outline, target keywords, and FAQ prompts are generated for you - you don’t need to provide or author them. You can still seed
primaryKeywords(one entry; extras are stored as secondary),secondaryKeywords,promptInsights,competitorUrls(up to 5),internalLinkTargetSlugs, andinternalLinkTargetUrls. - A draft is created and generation starts. The response is
{ slug, articleId, generating, started, status }(plusrequiredCredits/message/alreadyRunningwhen relevant). It is sent as a keep-alive stream (application/x-ndjson): leading whitespace is a heartbeat, and the final line is the JSON result. An error after streaming starts arrives as a{ success: false, error, code }line with HTTP 200. When credits run short the draft is still created and the final line hasstarted: falsewith codeINSUFFICIENT_CREDITS. A missing or invalidtopicIdreturns400before the stream opens. - Poll the status with that
slug; when generation finishes without an error, fetch the article.
Notes
- Topic is required. Every article belongs to a topic cluster. Pass a
topicIdfrom Topics, or create one with Create Topic. The topic name is taken from the cluster. - Length sets the cost.
lengthis required: short (800-1000 words, ~100 credits), medium (1800-2000, ~200), or long (2800-3000, ~300). If your credit balance can’t cover it, the draft is still created but generation does not start, and the response carriesrequiredCreditsand amessage. - Type (
type) islisticle(default),comparison,news,review, orguide. Other optional fields:contentArticleType(pillarorcluster),tone, andincludeTldr,includeFaq,includeConclusion,includeCta(default to your brand settings). Limited to 20 requests per minute. - Custom instructions (
customInstructions) are optional, per-article writing guidance. Your brand’s default content guidelines (Brand Settings → About) are always applied automatically. - Language is optional. Omit it and the article uses your brand’s Writing Language (Settings → Content & CMS → Articles), falling back to your brand’s default language. Pass a language code such as
esto write this one article in a different language. Codes are usually two letters, with three exceptions: Chinese iszh_CNorzh_TW, and Hebrew isiw(the legacy code, nothe). Whichever applies is recorded on the article, so later refreshes, audits, and editor commands stay in that language even if the brand setting changes. - Set
startGeneration: falseto create the draft only, then call Start Generation later.
Prefer step-by-step?
Use the wizard tools for granular control: Generate Titles → Generate Outline → Create Article → Start Generation.Authorizations
Your SnowSEO API key (sk_...).
Body
Article title / headline.
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.
Required length tier - short: 800–1000 words (~100 credits), medium: 1800–2000 words (~200 credits), long: 2800–3000 words (~300 credits). The tier sets the credit cost.
short, medium, long Team id (falls back to the session's active project).
Article type. Defaults to listicle.
listicle, comparison, news, review, guide Pillar or cluster role in a topic cluster. Omit for a standalone post.
pillar, cluster The one search term the article targets. Pass a single entry; extra entries are stored as secondary keywords.
Secondary keywords.
Questions / search intents the article should answer.
Up to 5 competitor article URLs to inform the outline's competitive analysis.
Writing tone (e.g. 'Professional', 'Casual'). Defaults to professional.
Optional free-text writing instructions for THIS article only (focus, angle, things to include or avoid). The brand's default content guidelines apply either way.
When true (default), the article's custom instructions apply together with the brand's content guidelines. When false, they replace the brand guidelines for this article.
Slugs of existing SnowSEO articles to link out to.
Absolute http(s) URLs to link out to.
Include a TL;DR section. Defaults to true.
Include an FAQ section. Defaults to true.
Include a conclusion (ignored for listicles). Defaults to true.
Include a CTA section. Defaults to false.
Start content generation now (default true). False creates only the draft.
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
A newline-delimited stream. Whitespace keeps the connection alive; status and final result are JSON lines. An error after streaming starts is returned as a JSON error line with HTTP 200.
Newline-delimited JSON events
Was this page helpful?

