Documentation
Integrations and API
Connect AutoBlog to your blog, CMS, or any HTTP endpoint. Delivery is one webhook — here is the exact contract.
How integration works
AutoBlog is the writer; your site is the publisher. On schedule, AutoBlog generates an article and POSTs it as JSON to a single webhook URL you control. Your endpoint stores the article (or forwards it to your CMS) and returns a 2xx. That's the whole contract — there is no polling and no SDK.
- You set one webhook URL per campaign in the dashboard.
- You may add a custom auth header (name + value) that AutoBlog sends on every request.
- AutoBlog POSTs a JSON body with event "article.created".
- Your endpoint stores or publishes the article and returns 2xx within 15 seconds.
- Non-2xx or timeout: AutoBlog marks it failed and you can resend from Content.
What your site must add
Your receiving site needs three things: a route that accepts POST JSON, a place to store the article, and a page that renders it once stored. From there, published articles are just rows in your database. Below is a complete minimal receiver.
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/blog/webhook', async (req, res) => {
// 1. Verify the shared secret header you configured in AutoBlog.
if (req.headers['x-blog-secret'] !== process.env.BLOG_WEBHOOK_SECRET) {
return res.status(401).json({ error: 'unauthorized' });
}
const { event, post } = req.body;
// 2. Remove on unpublish; otherwise upsert the article (idempotent on id).
if (event === 'article.removed') {
await db.posts.deleteOne({ id: post.id });
return res.json({ ok: true });
}
if (event !== 'article.created') return res.status(400).end();
await db.posts.updateOne(
{ id: post.id },
{ $set: {
id: post.id,
slug: post.slug,
title: post.title,
excerpt: post.excerpt,
body: post.body_html,
category: post.category,
tags: post.tags,
date: new Date(post.date)
} },
{ upsert: true }
);
// 3. Respond 2xx fast (AutoBlog times out after 15s).
res.json({ ok: true });
});
app.listen(7007);The payload
Every delivery is a single JSON object. body_html is ready-to-render HTML — sanitize it if you allow untrusted input, but it is generated by AutoBlog and safe to render. image_url is a hosted featured image (may be null if generation is disabled); image_alt is its alt text.
{
"event": "article.created",
"project_id": "65f2…ab9",
"post": {
"title": "How vector search works in 2026",
"slug": "how-vector-search-works-in-2026",
"excerpt": "Two to three sentence summary.",
"body_html": "<h2>Section</h2><p>Full article HTML…</p>",
"image_url": "https://autoblog.neoned71.com/images/post-…jpg",
"image_alt": "Featured image alt text",
"tags": ["vector-search", "databases", "ai"],
"category": "tech",
"date": "2026-09-15T08:00:00.000Z",
"reading_minutes": 6,
"sources": [{ "title": "Source name", "url": "https://…" }],
"keywords": ["vector search", "embeddings"]
}
}Authenticating deliveries
Configure a header name and value in the campaign settings. AutoBlog sends that exact header on every POST, so you can reject anything that does not match. A dedicated shared secret is better than reusing an API key.
// Header name: x-blog-secret
// Header value: <a long random string>
if (req.get('x-blog-secret') !== process.env.BLOG_WEBHOOK_SECRET) {
return res.sendStatus(401);
}Idempotency & retries
Delivery can be retried (manually from Content, or after a transient failure), so treat post.id as the unique key and upsert. Never create a second row for the same id. Return a 2xx as soon as the write is durable. If you kick off a slow rebuild, do it in the background and still return 200 — AutoBlog gives you 15 seconds.
// Idempotency keyed on the post id: repeat deliveries overwrite, never duplicate.
await db.posts.replaceOne({ id: post.id }, doc, { upsert: true });Rendering articles on your site
Once stored, a post is plain data: id, title, excerpt, category, tags, date, and body (HTML). Render it however your stack builds pages. You only need to read your own database — AutoBlog is not in the read path.
// Example route: /blog/[id]
const post = await db.posts.findOne({ id });
if (!post) return notFound();
return render(post.title, post.excerpt, post.body, post.date);Publish & unpublish
Each article has Publish and Unpublish controls in AutoBlog. Publishing sends (or re-sends) the article to your webhook. Unpublishing removes it from your site: AutoBlog POSTs an "article.removed" event with the post id, and your endpoint deletes that post. Handle both events.
// article.removed payload
{
"event": "article.removed",
"project_id": "65f2…ab9",
"post_id": "6ac0…19",
"post": { "id": "6ac0…19", "slug": "how-vector-search-works" }
}
// In your receiver:
if (event === 'article.removed') {
await db.posts.deleteOne({ id: post.id });
return res.json({ ok: true });
}Approval mode
If you want to review before anything reaches your site, turn on "Require approval before sending" on the campaign. AutoBlog then holds each article in the dashboard as pending; nothing is POSTed until you Publish. Rejected articles are never sent. Your endpoint does not change — it simply receives fewer, already-approved deliveries.
View links (Site URL)
Set a Site URL on the campaign (for example https://your-blog.com/blog). AutoBlog composes view links as Site URL + "/" + article id, so the Content list can open each article on your site. This is display-only; it does not affect delivery.
CMS shortcuts
If you do not want to build a receiver, point the webhook at a service that already accepts JSON:
Ghost
Create a Custom Integration in Ghost Admin, then have a small endpoint create a post via the Content/Admin API from the payload fields.
WordPress
Point the webhook at your own endpoint that calls the REST API (wp-json/wp/v2/posts) with title, content and tags, using an application password.
Zapier / Make
Use a webhook trigger, then map the payload fields into a CMS or a Google Doc for review.
Static sites
Receive the POST on a serverless function, write the post into your content store, then trigger your host’s deploy hook to rebuild.
REST API
Manage projects, keys, and webhooks programmatically with your API key as a bearer token.
curl -X POST https://autoblog.neoned71.com/api/projects \
-H "Authorization: Bearer ab_…" \
-H "Content-Type: application/json" \
-d '{ "name": "My Blog", "topics": ["ai", "tech"], "frequency": "2x" }'