API Documentation

The AutoBlog API lets you programmatically fetch AI-generated blog posts and newsletters (and hero images when present on a row). It is a RESTful JSON API served by the api-gateway Supabase Edge Function.

Available on SEO Engine ($49/mo) and Programmatic Pro ($149/mo) plans. See pricing.

Quick Start

Get your first API response in under 60 seconds.

1

Get your API key

Sign up at autoblogs.dev and open API Keys in the dashboard. Create a full key for server-side calls to content endpoints, or an embed key (analytics only, with allowed origins) for the browser tracking script. See API keys & scopes.

2

Make your first request

Use your API key in the Authorization header against the gateway URL to fetch your latest generated content.

3

Publish

Parse the JSON response and publish the HTML body, image, and metadata to your CMS or website.

// Minimal integration example (gateway = Supabase Edge Function URL)
const API_BASE = process.env.AUTOBLOG_API_BASE ?? 'https://YOUR_REF.supabase.co/functions/v1/api-gateway';
const response = await fetch(`${API_BASE}/v1/content/latest`, {
  headers: { 'Authorization': `Bearer ${process.env.AUTOBLOG_API_KEY}` }
});
const { data } = await response.json();

// data.body_html, data.meta_title, data.slug
// data.id          - UUID (use in URLs and analytics)
// data.image_url   - Hero image URL when set

Authentication

Authenticate with either:

  • API key: Authorization: Bearer <api_key>. Create and revoke keys under API Keys in the dashboard.
  • Dashboard session: Supabase JWT in Authorization: Bearer <jwt> (token starts with eyJ), or the same token in x-supabase-session. Used by the logged-in app; not for public embeds.
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Security. Do not put a full API key in client-side bundles. Use server-side requests, or an embed key only for browser analytics (see API keys & scopes).

API keys & scopes

Each key has one or more scopes that limit what it can call. If scopes are not set on a key, the API defaults to allowing both content_read and analytics_ingest.

ScopeAllows
content_read GET /v1/content, GET /v1/content/:id (UUID), GET /v1/content/latest, GET /v1/content/by-slug, GET /v1/analytics/summary, GET/POST /v1/projects, and related content routes. Required for normal server integrations.
analytics_ingest POST /v1/analytics/events only. Used by embed keys for the tracking script.

Full key: Typically includes content_read (and may include analytics where your plan allows). Use only on servers, CI, or trusted tools.

Embed key: Scoped to analytics_ingest. Safe in the browser when you set allowed origins so only your domains can send events. The API checks the Origin or Referer header against that list.

Base URL

The REST API is implemented by the api-gateway Supabase Edge Function. Replace YOUR_REF with your Supabase project reference (same subdomain you use for the dashboard client).

https://YOUR_REF.supabase.co/functions/v1/api-gateway

Endpoints are prefixed with /v1. Example:

GET https://YOUR_REF.supabase.co/functions/v1/api-gateway/v1/content/latest

In server code, set AUTOBLOG_API_BASE to the gateway URL (no trailing slash), then call ${AUTOBLOG_API_BASE}/v1/....

All requests and responses use JSON. Set Content-Type: application/json for POST bodies.

The same function also implements POST /v1/auth/signup and POST /v1/auth/login for the in-app auth flow (email/password). Third-party integrations normally use API keys instead.

Scheduled publishing

Recurring schedules and publish times are configured in the dashboard per content source. The API does not create schedules; it returns content that is already published (or other statuses if you ask for them).

Use GET /v1/content with status=published (the default) and limit / offset to page through results. For automation patterns, see Integrations.

Rate Limits

The gateway does not send X-RateLimit-* headers. Plan-based usage (posts per month, etc.) is enforced in the product and billing layer.

For POST /v1/content/generate calls made with an API key, the gateway compares your plan to a per-minute ceiling before running generation: 10/min on SEO Engine (seo_engine) and 30/min on Pro (pro). Other routes are not individually throttled inside this function.

Error Handling

Errors return JSON with "status": "error", a message string, and sometimes a code string (for example "PAYMENT_REQUIRED"), not the HTTP status duplicated as a number.

{
  "status": "error",
  "message": "Authentication required"
}
HTTPMeaningTypical cause
400Bad RequestMissing query/body fields, invalid JSON, or invalid date range.
401UnauthorizedNo valid API key or session token.
402Payment requiredAccount not active (e.g. subscription not completed); analytics/content may return PAYMENT_REQUIRED.
403ForbiddenWrong plan for API/analytics, missing scope on the key, or origin not allowed (analytics).
404Not FoundUnknown route or no matching content.
429Too many requestsGeneration rate limit exceeded for your plan.
500Server errorUpstream or configuration issue. Retry or contact support.
GET /v1/content/latest

Returns the most recently generated content for the authenticated project. This is the primary endpoint most integrations will use.

Query Parameters

type string optional

Filter by content type. Values: blog_post, newsletter. Defaults to blog_post.

status string optional

Same as list: published (default), or all for any status.

Example: JavaScript (Node.js / Next.js)

const AUTOBLOG_API_KEY = process.env.AUTOBLOG_API_KEY;
const API_BASE = process.env.AUTOBLOG_API_BASE ?? 'https://YOUR_REF.supabase.co/functions/v1/api-gateway';

async function getLatestPost(type = 'blog_post') {
  const response = await fetch(
    `${API_BASE}/v1/content/latest?type=${type}`,
    {
      headers: {
        'Authorization': `Bearer ${AUTOBLOG_API_KEY}`,
        'Content-Type': 'application/json'
      }
    }
  );

  if (!response.ok) {
    throw new Error(`AutoBlog API error: ${response.status}`);
  }

  const json = await response.json();
  return json.data;
}

// Usage
const post = await getLatestPost();
console.log(post.meta_title);     // "The Complete Guide to..."
console.log(post.slug);            // "plumbing-maintenance-guide"
console.log(post.body_html);       // "<h1>The Complete...</h1>..."
console.log(post.image_url);       // hero image URL or null
console.log(post.newsletter_html); // newsletter HTML or null

Example: Python

import os
import requests

API_KEY = os.environ["AUTOBLOG_API_KEY"]
API_BASE = os.environ.get("AUTOBLOG_API_BASE", "https://YOUR_REF.supabase.co/functions/v1/api-gateway")

def get_latest_post(content_type="blog_post"):
    response = requests.get(
        f"{API_BASE}/v1/content/latest",
        headers={"Authorization": f"Bearer {API_KEY}"},
        params={"type": content_type}
    )
    response.raise_for_status()
    return response.json()["data"]

post = get_latest_post()
print(post["meta_title"])
print(post["body_html"][:200])

Example: cURL

curl -s "https://YOUR_REF.supabase.co/functions/v1/api-gateway/v1/content/latest?type=blog_post" \
  -H "Authorization: Bearer YOUR_API_KEY" | jq .

Response (200 OK)

See Response Schema for full field documentation.

{
  "status": "success",
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "content_type": "blog_post",
    "status": "published",
    "created_at": "2026-04-06T10:00:00.000Z",
    "project_id": "660e8400-e29b-41d4-a716-446655440001",
    "meta_title": "The Complete Guide to Home Plumbing Maintenance",
    "meta_description": "Prevent burst pipes and expensive leaks with our comprehensive checklist.",
    "slug": "home-plumbing-maintenance-guide",
    "body_html": "<h1>...</h1><p>...</p>",
    "body_text": "Plain text excerpt...",
    "newsletter_html": null,
    "image_url": "https://…",
    "image_alt_text": "Copper pipes and pressure gauge",
    "keywords": ["plumbing"],
    "word_count": 1420,
    "reading_time": "6 min"
  }
}
GET /v1/content

Returns a list of generated content for the authenticated account, ordered by created_at (newest first). Use limit and offset to page through results.

Query Parameters

type string optional

Filter: blog_post or newsletter (alias: content_type).

project_id string optional

Filter by project (Pro plan).

status string optional

Filter by row status. Defaults to published. Use all to include drafts and scheduled items.

limit integer optional

Max items (default 20, max 100).

offset integer optional

Skip this many rows (for pagination).

Blog page integration

Point your website’s /blog route at this API (server-side, with your API key). List posts with status=published (default), then link each card to a detail view that loads by slug or id.

// Example: blog index (Node / Edge)
const API_BASE = process.env.AUTOBLOG_API_BASE ?? 'https://YOUR_REF.supabase.co/functions/v1/api-gateway';
const res = await fetch(
  `${API_BASE}/v1/content?type=blog_post&status=published&limit=20`,
  { headers: { Authorization: `Bearer ${API_KEY}` } }
);
const { data } = await res.json();
// data[].slug, data[].meta_title, data[].body_html, data[].created_at

Single post by slug: GET /v1/content/by-slug?slug=my-post&status=published (SEO Engine / Pro).

Response (200 OK)

The response is a JSON array of content rows (same shape as GET /content/:id). There is no total count in the payload; increase offset until you receive fewer than limit items.

{
  "status": "success",
  "data": [
    { /* same shape as single content object */ },
    { /* ... */ }
  ]
}

Analytics embed script

Track views, time on page, and outbound clicks from your live site. Browser traffic uses an embed API key and the optional script below; server-side tools and MCP use GET /v1/analytics/summary with a full key.

POST /v1/analytics/events

POST /v1/analytics/events

With an API key, the key must include the analytics_ingest scope, and you must configure at least one allowed origin; the request’s Origin or Referer must match. Session tokens (JWT from the dashboard) authenticate as you without an API key record, so the allowed-origin list is not enforced for that path. Browser embeds should always use an embed key.

Events are stored for your user; unknown content_id values or invalid event_type values are skipped (partial insert).

Send at most 50 events per request body. Successful responses include how many rows were inserted (events targeting valid content may be fewer than the array length).

Request body

{
  "events": [
    {
      "content_id": "uuid",
      "event_type": "view" | "heartbeat" | "link_click",
      "session_id": "opaque-id",
      "payload": { "dwell_ms": 15000, "href": "https://..." },
      "client_ts": "2026-01-01T12:00:00.000Z"
    }
  ]
}

Response (200 OK)

{ "status": "success", "data": { "inserted": 3 } }

GET /v1/analytics/summary

GET /v1/analytics/summary

Requires a full API key with the content_read scope (embed keys cannot call this route). Available on SEO Engine and Pro when analytics is enabled for your account.

Query parameters

from string optional

Start of range (ISO date or datetime). Defaults to 30 days before to.

to string optional

End of range (ISO date or datetime). Defaults to now.

Aggregates use server receive time with from inclusive and to exclusive. Only posts with at least one event in the window appear.

Response (200 OK)

{
  "status": "success",
  "data": [
    {
      "content_id": "uuid",
      "meta_title": "Example post",
      "slug": "example-post",
      "views": 42,
      "total_dwell_ms": 125000,
      "clicks": 5
    }
  ]
}

Embed script (copy-paste)

Host /js/autoblog-track.js from this site or copy the file to your CDN. On each post detail page, add:

<script src="https://autoblogs.dev/js/autoblog-track.js"
  data-gateway="https://YOUR_REF.supabase.co/functions/v1/api-gateway"
  data-site-key="ab_live_…"
  data-content-id="POST_UUID_FROM_DASHBOARD"
  async></script>

No-code builders

  • Wix: Settings → Custom Code → Add code to All pages or the blog post template → paste the <script> (use the post’s content UUID in data-content-id; you may use Velo to inject it dynamically).
  • Framer: Site Settings → Custom Code, or a Code component on your blog article template; pass the CMS item’s id into data-content-id.
  • Lovable: Add the script in your root layout or article page; map route params to data-content-id.

Analytics may require cookie or consent banners depending on your region. Consult your legal advisor. The embed sends first-party events to AutoBlog only.

GET /v1/content/:id

Returns a single content item by primary key. The path segment must be a UUID (the id column on content).

Path Parameters

id uuid required

Example: 550e8400-e29b-41d4-a716-446655440000. Returned in list and fetch responses as data.id.

Response

Same shape as the single content object in GET /content/latest.

POST /v1/content/generate SEO Engine & Pro

Runs a synchronous Gemini call and inserts a new draft row. Requires an active subscription (profile.status === active). With an API key, your plan must be SEO Engine or Pro; the gateway also enforces per-minute generation caps (10/min vs 30/min).

The implementation in api-gateway is intentionally minimal: it sends your topic (and optional keywords) to the model and persists the parsed JSON. It does not substitute template variables in topic, and it does not accept word_count, image_style, or generate_image in the request body. Those fields are ignored if sent.

Request body

type string required

blog_post or newsletter (must satisfy the database check constraint).

topic string required

Topic line passed into the model prompt.

keywords string[] optional

Joined into the prompt for the model.

project_id uuid optional

If set, voice sliders/sample are taken from this project; otherwise optional voice fields on the body can supply voice_mode, voice_instructions, formality, energy, personality for the prompt builder.

Example request

const API_BASE = process.env.AUTOBLOG_API_BASE ?? 'https://YOUR_REF.supabase.co/functions/v1/api-gateway';
const response = await fetch(`${API_BASE}/v1/content/generate`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    type: 'blog_post',
    topic: 'Winter plumbing checklist for homeowners',
    keywords: ['frozen pipes', 'maintenance']
  })
});

const { data } = await response.json();
// data is the inserted content row (draft) or parsed model output on save failure

Response (201 Created)

Returns { "status": "success", "data": <content row> } where data matches the database shape (blog posts expect meta_title, body_html, body_text from the model). Richer generation (images, scheduling, full SEO pipeline) uses other app flows such as the generate-content function, not this minimal route.

POST /functions/v1/repurpose-content Pulse / SEO Engine / Pro

Generate distribution variants from an existing content item. This endpoint is an Edge Function and is invoked with supabase.functions.invoke(), not through api-gateway.

Requires an authenticated dashboard session JWT. Plan gating applies by format: Pulse supports summary output; SEO Engine and Pro support all formats.

Request body

content_id uuid required

The source content row to repurpose.

formats string[] required

Requested output formats. Supported values include twitter_thread, linkedin_post, newsletter_teaser, and summary.

Example invoke

const { data, error } = await supabase.functions.invoke('repurpose-content', {
  body: {
    content_id: '550e8400-e29b-41d4-a716-446655440000',
    formats: ['twitter_thread', 'linkedin_post', 'summary']
  }
});

Response shape

{
  "status": "success",
  "data": {
    "content_id": "uuid",
    "variants": {
      "twitter_thread": "...",
      "linkedin_post": "...",
      "newsletter_teaser": "...",
      "summary": "..."
    }
  }
}
POST /functions/v1/generate-insights SEO Engine & Pro

Generate plain-English analytics insights for a selected date range. This endpoint is an Edge Function called via supabase.functions.invoke(), not through api-gateway.

Requires an authenticated dashboard session JWT and an active plan that includes AI insights.

Request body

from string optional

Start of range (ISO date or datetime).

to string optional

End of range (ISO date or datetime).

Example invoke

const { data, error } = await supabase.functions.invoke('generate-insights', {
  body: {
    from: '2026-03-01T00:00:00.000Z',
    to: '2026-04-01T00:00:00.000Z'
  }
});

Response shape

{
  "status": "success",
  "data": {
    "insights": [
      {
        "type": "opportunity",
        "title": "Publishing window is outperforming baseline",
        "detail": "..."
      }
    ]
  }
}

Response Schema

Content endpoints return rows from the public.content table (JSON field names match column names). There is no nested image object. Hero image fields are flat.

FieldTypeDescription
iduuidPrimary key. Use in GET /v1/content/:id, analytics content_id, and embed data-content-id.
content_typestringblog_post or newsletter.
statusstringdraft, published, scheduled, or archived.
created_atstringISO 8601 timestamp.
updated_atstringISO 8601 timestamp.
project_iduuid|nullOptional project association.
meta_titlestring|nullPage title / SEO title.
meta_descriptionstring|nullSEO description.
slugstring|nullURL slug when set.
body_htmlstring|nullArticle HTML for blog posts.
body_textstring|nullPlain text body.
subject_linestring|nullNewsletter subject (when applicable).
newsletter_htmlstring|nullNewsletter HTML (when applicable).
image_urlstring|nullHero image URL when present.
image_alt_textstring|nullAlt text for the hero image.
image_stylestring|nullStyle enum when set (see Image Styles).
keywordsstring[]Keyword list stored on the row.
word_countinteger|nullWord count when populated.
reading_timestring|nullEstimated reading time when populated.
tonestring|nullTone or voice metadata (may reflect sliders/sample mode).

Content Types

TypeValueDescription
Blog Postblog_postSEO-optimized article with structured HTML, meta tags, and slug. Designed for website publishing.
NewsletternewsletterEmail-safe HTML with inline styles, subject line, and preview text. Compatible with all major ESPs.

On-demand generation via POST /v1/content/generate sets type to a single value per request (blog_post or newsletter); there is no combined both mode in the gateway.

Image Styles

Allowed values for image_style on stored content (for example when set by the dashboard or full generate-content pipeline). The minimal api-gateway POST /v1/content/generate route does not currently persist image_style or generate images.

ValueDescription
photorealisticHigh-quality, realistic photography style. Best for most business and editorial use cases.
illustrationClean, modern vector illustration. Good for tech and SaaS blogs.
minimalSimple, low-detail compositions with lots of whitespace. Good for clean brands.
abstractArtistic, non-representational visuals. Good for creative and design-focused content.
editorialMagazine-style editorial photography. Good for lifestyle and fashion content.
infographicData-visualization style with charts and diagrams. Best for technical or data-driven posts.

Webhooks

This codebase does not expose a public “outbound” webhook that POSTs to your URL on every new post. Stripe and other billing webhooks are internal to the platform.

For inbound idea capture, projects can POST to https://YOUR_REF.supabase.co/functions/v1/idea-webhook with header x-webhook-secret matching the project’s configured secret (rate-limited per secret).

To detect new published content from your stack, poll GET /v1/content on a schedule or integrate from the dashboard workflows you already use.

MCP server (Cursor & Claude Desktop)

This project ships a Model Context Protocol server so assistants can list posts, read analytics summaries, and show embed instructions. Code lives under packages/autoblog-mcp (run npm install in that folder).

Requirements: Node.js 18+, SEO Engine or Pro, and a full API key with content_read and analytics_ingest (see package README). Set:

export AUTO_BLOG_BASE_URL="https://YOUR_REF.supabase.co/functions/v1/api-gateway"
export AUTO_BLOG_API_KEY="ab_live_…"
node /path/to/packages/autoblog-mcp/index.js

Tools exposed: list_blog_posts, get_analytics_summary, get_embed_instructions. In Cursor or Claude Desktop, add an MCP server entry that runs node with the absolute path to index.js and the environment variables above.

Integration: Next.js

Fetch your latest blog post at build time or on each request using Next.js server components or API routes.

Server Component (App Router)

// app/blog/latest/page.tsx
async function getPost() {
  const API_BASE = process.env.AUTOBLOG_API_BASE ?? 'https://YOUR_REF.supabase.co/functions/v1/api-gateway';
  const res = await fetch(`${API_BASE}/v1/content/latest`, {
    headers: { 'Authorization': `Bearer ${process.env.AUTOBLOG_API_KEY}` },
    next: { revalidate: 3600 } // revalidate every hour
  });
  const json = await res.json();
  return json.data;
}

export default async function LatestBlogPage() {
  const post = await getPost();

  return (
    <article>
      <head>
        <title>{post.meta_title}</title>
        <meta name="description" content={post.meta_description} />
      </head>
      {post.image_url && (
        <img src={post.image_url} alt={post.image_alt_text || ''} width={1200} height={630} />
      )}
      <div dangerouslySetInnerHTML={{ __html: post.body_html }} />
    </article>
  );
}

Integration: WordPress

Use a cron job or WP-CLI command to fetch content and create WordPress posts automatically.

// functions.php - Add to your theme or as a custom plugin
function autoblog_fetch_latest() {
  $response = wp_remote_get('https://YOUR_REF.supabase.co/functions/v1/api-gateway/v1/content/latest', [
    'headers' => [
      'Authorization' => 'Bearer ' . AUTOBLOG_API_KEY,
    ]
  ]);

  $body = json_decode(wp_remote_retrieve_body($response), true);
  $post_data = $body['data'];

  // Create a new WordPress post
  wp_insert_post([
    'post_title'   => $post_data['meta_title'],
    'post_content' => $post_data['body_html'],
    'post_name'    => $post_data['slug'],
    'post_status'  => 'draft',
    'post_type'    => 'post',
  ]);
}

// Run weekly via WP-Cron
add_action('autoblog_weekly_fetch', 'autoblog_fetch_latest');
if (!wp_next_scheduled('autoblog_weekly_fetch')) {
  wp_schedule_event(time(), 'weekly', 'autoblog_weekly_fetch');
}

Integration: Generic REST (Any Stack)

AutoBlog works with any language or framework that can make HTTP requests. Here is the minimal pattern:

# 1. Set your API key as an environment variable
export AUTOBLOG_API_KEY="your_key_here"
export AUTOBLOG_API_BASE="https://YOUR_REF.supabase.co/functions/v1/api-gateway"

# 2. Fetch the latest blog post
curl -s "${AUTOBLOG_API_BASE}/v1/content/latest" \
  -H "Authorization: Bearer $AUTOBLOG_API_KEY" \
  -o latest_post.json

# 3. Extract the HTML body
cat latest_post.json | jq -r '.data.body_html' > post.html

# 4. Download the image
curl -s $(cat latest_post.json | jq -r '.data.image_url // empty') -o hero.jpg
Tip. Set up a cron job to run this script weekly and your blog will publish itself. Most hosting providers (Vercel, Railway, Render) support scheduled tasks natively.

Ready to integrate?

Get your API key and start fetching content in under 60 seconds.

Get Started