KoalaWriter API
The KoalaWriter API is the best API for creating SEO-optimized articles. It is billed based on the number of words generated, the same as if you were using KoalaWriter manually. All paid plans can use this API with no additional costs.
How It Works
The KoalaWriter API is asynchronous, meaning the article is created in the background. The process works as follows:
- Make an API call to queue an article for writing
- Call the API to check the status of the article
- Once the status is
finished, access the full HTML of the completed article
When an article is completed, it is automatically saved to your account so you can also access it there.
You can specify an integrationId so that when the article is completed it will automatically be created as a draft in WordPress, Shopify, Webflow, etc! Webhooks are also supported by specifying the webhookUrl parameter.
If you are just wanting to do bulk writing, please check out the Bulk Mode in KoalaWriter.
Endpoints
Creating an Article (v2)
POST https://koala.sh/api/articles/v2/
The v2 endpoint uses a new generation engine for higher quality articles. For the legacy v1 engine, use /api/articles/ instead — see the Legacy v1 section below.
Example Request (v2)
fetch("https://koala.sh/api/articles/v2/", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
targetKeyword: "can you eat watermelon seeds?",
gptVersion: "gpt-5.2",
realTimeData: true,
shouldCiteSources: true,
multimediaOption: "images",
imageStyle: "photo",
brandId: "your-brand-uuid",
brandMentionLevel: "subtle",
articleInstructions: "Focus on health benefits. Write from a nutritionist's perspective.",
}),
});Example Response
{"articleId": "7b53671d-da26-4ab1-b096-6e014125f712"}Parameters
Below is a full list of parameters for the v2 endpoint. Only the targetKeyword is required.
| Name | Type / Possible Values | Description |
|---|---|---|
| targetKeyword | string (required) | The main keyword for the article. |
| articleType | "blog_post" (default), "listicle", "service_page", "amazon_product_roundup", "youtube_video", "rewrite_blog_post", "amazon_single_product_review", "local_places_roundup" | The type of article to generate. |
| gptVersion | "gpt-5-mini" (default), "gpt-5.2", "claude-4.5-sonnet" | The model to use. |
| language | "English" (default) or any language supported by KoalaWriter | The language of the article. |
| pointOfView | "third_person" (default), "first_person_singular", "first_person_plural", "second_person" | The point of view for the article. |
| toneOfVoiceProfile | "seo_optimized" (default), "automatic", or any string (e.g. "Friendly") | The writing style for the article. Use "automatic" to have the AI generate a tailored writing style during outline generation, or "custom" with a toneOfVoice parameter for your own style. |
| title | string | Provide a title if you don't want one generated automatically. |
| readabilityMode | "default" or "8th_grade" | Set to "8th_grade" for shorter sentences and simpler language. |
| integrationId | string | Integration ID for a connected site to auto-create a draft. |
| webhookUrl | string | URL to POST to when the article is completed. Payload matches the /api/articles/{article_id} response. |
| v2-only parameters | ||
| articleInstructions | string | Free-form instructions to guide article generation (e.g. "Focus on budget-friendly options, write from a beginner's perspective"). |
| brandId | string | UUID of a brand created in Brand DNA. The article will be written with your brand's voice, knowledge, and context. Supported for blog_post, listicle, and service_page. |
| brandMentionLevel | "subtle" (default), "prominent", "none" | How prominently the brand is mentioned. "prominent" adds a dedicated section; "subtle" mentions where relevant; "none" uses brand knowledge for accuracy without naming it. |
| Research & real-time data (blog_post, service_page) | ||
| realTimeData | boolean, defaults to false | Whether to use real-time data for the article. |
| enableDeepResearch | boolean, defaults to false | Enable Deep Research. Only used when realTimeData is true. |
| shouldCiteSources | boolean, defaults to true | Whether to include links to sources used. |
| realTimeDataSource | "web", "scholarly", "news", "custom" | Source of real-time data. Only used when realTimeData is true. |
| realTimeDateRange | "" (all time, default), "past_hour", "past_day", "past_week", "past_month", "past_year" | Time range for news data. Only used when realTimeDataSource is "news". |
| country | string | The country to target in the article. |
| urls | array of strings | URLs to use as references. |
| Content structure (blog_post) | ||
| includeFaq | boolean, defaults to false | Add a FAQ section based on real-time data. |
| includeKeyTakeaways | boolean, defaults to false | Include a Key Takeaways section in the introduction. |
| disableIntroduction | boolean | Disable the introduction. |
| disableConclusion | boolean | Disable the conclusion. |
| articleLength | "default", "custom", "short", "shorter", "medium", "long", "longer" | Article length. Set to "custom" to use numberOfSections. |
| numberOfSections | integer | Number of sections. Requires articleLength set to "custom". |
| outline | array of Sections | Custom outline. See documentation. By default, an outline is generated from the keyword. |
| extraOutlinePrompt | string | Section names (one per line, indent for H3s) to guide outline generation. Use outline for full control. |
| seoOptimizationLevel | "default", "manual", "ai_powered" | SEO optimization mode. |
| extraEntitiesPrompt | string | Comma-separated keywords/entities to cover. Only used when seoOptimizationLevel is "manual". |
| internalLinkingDomainId | string | Domain ID for internal linking. Find it in the URL when viewing a domain in KoalaLinks. |
| Custom prompts | ||
| extraTitlePrompt | string | Additional prompt for the article title. |
| extraSectionPrompt | string | Additional prompt applied to each section. |
| extraIntroductionPrompt | string | Additional prompt for the introduction. |
| Multimedia (blog_post, listicle) | ||
| multimediaOption | "none" (default), "auto", "images", "videos" | Type of multimedia to include. |
| imageStyle | "illustration" (default), "photo", "watercolor", "fantasy", "anime", "isometric" | Style of AI-generated images. |
| imageModel | "gpt-image-2-fast" (default), "gpt-image-2-medium", "ideogram-3.0-turbo", "nano-banana-2" | Model for generating AI images. |
| maxImages | integer | Maximum number of images. |
| imageSize | string | Image size (must be a supported size listed here). |
| maxVideos | integer | Maximum number of videos. |
| Auto-Polish | ||
| autoPolish | boolean, defaults to false | Automatically run Polish on the completed article. |
| polishSettings | object, defaults to {"split-up-long-paragraphs":true,"remove-mid-article-conclusions":true,"remove-repetitive-sentences":true,"convert-passive-voice":false,"simplify-complex-sentences":false,"humanize":false} | Polish settings. Requires autoPolish: true. |
| polishCustomInstructions | string (max 1,024 chars) | Custom instructions for Polish. Requires autoPolish: true. |
| Call-to-action (blog_post, listicle, service_page) | ||
| includeCta | boolean | Whether to include a call-to-action section at the end of the article. |
| ctaPrompt | string | Custom prompt for the CTA section. Requires includeCta: true. |
| listicle and local_places_roundup parameters | ||
| enableSupplementalInformation | boolean, defaults to true | Add 1-3 relevant sections at the end of the article. Recommended for comprehensive, optimized articles. |
| enableAutomaticLength | boolean, defaults to true | Automatically detect the number of items from the keyword (e.g. "5 cutest dog breeds" uses 5). Set to false to use numberOfItems. |
| numberOfItems | integer, default 10 | Number of items. Requires enableAutomaticLength: false. |
| extraListItemPrompt | string | Additional prompt applied to each list item. |
| amazon_product_roundup parameters | ||
| amazonDomain | "amazon.com" (default) or any Amazon domain supported by KoalaWriter | Amazon store domain to search. |
| numAmazonProducts | integer 1-48, defaults to 10 | Number of Amazon products to include. |
| enableFirstHandExperience | boolean, defaults to true | Include first-hand experience with the products. |
| amazonAssociatesId | string | Amazon Associates ID for affiliate linking. |
| amazonProductSearchUrl | string | Amazon product search URL to use. |
| youtube_video parameters | ||
| youTubeVideoUrl | string | URL of the YouTube video. |
| rewriteAllSourceData | boolean | Whether to rewrite all source data from the video. |
| rewrite_blog_post parameters | ||
| articleUrl | string | URL of the article to rewrite. |
| rewriteAllSourceData | boolean | Whether to rewrite all source data from the article. |
| amazon_single_product_review parameters | ||
| asin | string | Amazon Standard Identification Number for the product. |
| enableCondensedMode | boolean | Enable condensed mode for the product review. |
Checking Article Status
GET https://koala.sh/api/articles/{article_id}
Check the status of an article and retrieve the HTML when finished.
Example Response (Completed)
{
"config": {
"targetKeyword": "are great danes good pets?"
},
"status": "finished",
"statusDetail": "Finished article",
"updatedAt": 1683095362612,
"progress": 1,
"error": null,
"output": {
"html": "<h1>Are Great Danes Good Pets? Pros and Cons You Need to Know</h1>...",
"polishedHtml": null
}
}polishedHtml will be null unless autoPolish was set to true or the article was manually polished.
Example Response (In Progress)
{
"config": {
"targetKeyword": "are great danes good pets?"
},
"status": "processing",
"statusDetail": "Writing section 3",
"updatedAt": 1683095271489,
"progress": 0.33,
"error": null
}Status Values
queued: Article is queuedprocessing: Article is being writtenfinished: Article is finishedfailed: An error occurred
Complete Example
async function createAndWaitForArticle(keyword) {
try {
// Step 1: Create the article
const createResponse = await fetch("https://koala.sh/api/articles/v2/", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
targetKeyword: keyword,
gptVersion: "gpt-5.2",
realTimeData: true,
shouldCiteSources: true,
}),
});
if (!createResponse.ok) {
throw new Error(`Failed to create article: ${createResponse.status}`);
}
const { articleId } = await createResponse.json();
console.log(`Article created with ID: ${articleId}`);
// Step 2: Poll for article status
let article = null;
while (true) {
const statusResponse = await fetch(
`https://koala.sh/api/articles/${articleId}`,
{
headers: { Authorization: "Bearer YOUR_API_KEY" },
}
);
if (!statusResponse.ok) {
throw new Error(`Failed to check status: ${statusResponse.status}`);
}
article = await statusResponse.json();
if (article.status === "finished") {
console.log("Article is complete!");
break;
} else if (article.status === "failed") {
throw new Error(`Article failed: ${article.error}`);
}
console.log(`${article.status} - ${article.statusDetail || "In progress"} (${Math.round(article.progress * 100)}%)`);
await new Promise(resolve => setTimeout(resolve, 5000));
}
console.log("Article HTML:", article.output.html);
return article;
} catch (error) {
console.error("Error:", error);
return null;
}
}
createAndWaitForArticle("best hiking trails in colorado");Error Handling
- 400 Bad Request: Invalid parameters or request format
- 401 Unauthorized: Invalid or missing API key
- 500 Internal Server Error: Server-side error
Migrating from v1
If you have an existing v1 integration, upgrading to v2 is straightforward. Most parameters are unchanged.
Legacy v1 API
DeprecatedThe v1 engine generates articles section-by-section. It is still supported but we recommend using v2 for all new integrations. To use v1, send requests to /api/articles/ instead of /api/articles/v2/.
Need Help?
If you need additional assistance with the KoalaWriter API, please contact us.