Skip to main content
The Blog pillar is a full content engine — not a header-and-body table. Posts have categories and tags, scheduling, multi-language translations, featured images, SEO meta, and a research → write → image → translate → publish pipeline that runs as one async job.

What this gives you

  • Posts with draft, scheduled, published, archived lifecycle.
  • Translations per language with their own title, content, excerpt, and SEO meta.
  • Categories and tags with slugs, attached many-to-many.
  • Scheduling — set scheduled_at and we publish at the precise minute.
  • AI authoring pipeline — one POST kicks off topic research, writing, image generation, translation to every target language, and SEO meta.

Quick example

Create a published post in English, then async-translate it into French:
import { NeuralDraftClient } from "@neuraldraft/sdk";

const nd = new NeuralDraftClient({ apiKey: process.env.NEURALDRAFT_API_KEY! });

// Manual create (0 credits beyond plan post-quota). The SDK sets type="manual".
const post = await nd.blogPosts.create({
  title: "Five things we shipped this week",
  content: "<p>It was a busy week.</p>",
  excerpt: "Highlights from the past seven days.",
  language_code: "en",
  status: "published",
});

// Async translate — returns a Job; 7 credits per language.
const job = await nd.blogPosts.translate(post.id, ["fr"]);
await nd.jobs.poll(job.id);

Common workflows

1. Generate a multi-language post end to end

The headline workflow. One POST kicks off the full pipeline (research → outline → write → featured-image → SEO meta → per-language translations) and returns a Job reference. Subscribe to blog_post.published for the finished result, or poll.
SDK
const job = await nd.blogPosts.generateAi({
  topic: "Why API-first beats site-builder-first for SMBs",
  style: "thought_leadership",
  word_count: 1200,
  primary_keyword: "API-first CMS",
  translate_to_all: true, // translate into every project target language
  enable_research: true,
});

const finished = await nd.jobs.poll(job.id, { timeoutMs: 10 * 60_000 });
// finished.result?.blog_post_id
cURL
# Same endpoint as manual create — discriminator: type=ai
curl -X POST https://api.neuraldraft.io/v1/blog-posts \
  -H "Authorization: Bearer $NEURALDRAFT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "ai",
    "topic": "Why API-first beats site-builder-first for SMBs",
    "style": "thought_leadership",
    "word_count": 1200,
    "primary_keyword": "API-first CMS",
    "translate_to_all": true,
    "enable_research": true
  }'
Cost: 60 credits for the post itself (blog_post — covers research, draft, and featured image). Per-language translations charge 7 credits each (translate_language) on top, billed when each language lands.

2. Schedule a post for next Tuesday

SDK
await nd.blogPosts.schedule(4711, "2026-05-19T09:00:00Z");
// Or: nd.blogPosts.schedule(4711, new Date(...))
cURL
curl -X POST https://api.neuraldraft.io/v1/blog-posts/4711/schedule \
  -H "Authorization: Bearer $NEURALDRAFT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"scheduled_at":"2026-05-19T09:00:00Z"}'
The post enters scheduled state. At the exact minute we transition it to published and fire the blog_post.published webhook.

3. Edit and republish

Patch a published post in-place. Text fields (title, content, excerpt, meta_title, meta_description) write to the translation row resolved by language_code (default en); post-level fields (slug, status, category_id, featured_image) write to the post itself.
SDK
await nd.blogPosts.update(4711, {
  title: "Five things we shipped (updated)",
  language_code: "en",
});
cURL
curl -X PATCH https://api.neuraldraft.io/v1/blog-posts/4711 \
  -H "Authorization: Bearer $NEURALDRAFT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title":"Five things we shipped (updated)","language_code":"en"}'

4. Translate an existing post into a new language

SDK
const job = await nd.blogPosts.translate(4711, ["es", "it"]);
await nd.jobs.poll(job.id);
Cost: 7 credits per language (translate_language).

5. Lifecycle helpers

SDK
await nd.blogPosts.publish(4711);
await nd.blogPosts.unpublish(4711);
await nd.blogPosts.delete(4711);

// List + filter
const { data: drafts } = await nd.blogPosts.list({
  status: "draft",
  page_size: 20,
  sort: "-created_at",
});

Reference

EndpointTag
GET /v1/blog-postsBlog
POST /v1/blog-postsBlog
GET /v1/blog-posts/{slug}Blog
PUT /v1/blog-posts/{id}Blog
POST /v1/blog-posts/{id}/publishBlog
POST /v1/blog-posts/{id}/scheduleBlog
POST /v1/blog-posts/{id}/unpublishBlog
GET /v1/blog-posts/{id}/translationsBlog
PUT /v1/blog-posts/{id}/translations/{lang}Blog
GET /v1/categoriesBlog
GET /v1/tagsBlog
POST /v1/jobs (blog_post.generate)Jobs
GET /v1/blog/topic-suggestionsBlog