Content API
Your site's server code reads its pages, SEO tags and sitemap from SuperDuperSEO, then renders them on your own domain. The SDK wraps all of this.
- Base URL:
https://content.superduperseo.com/v1/ - Auth:
Authorization: Bearer <site key>(sds_live_...). The key selects the site. Create it with the MCP toolcreate_site_key, or in the app on the site's Content API page. - Server side only. Keep the key in your server environment (e.g.
SUPERDUPERSEO_CONTENT_KEY), never in code or the browser. There is no CORS, so browsers cannot call the API. - Never public, never indexed. Without a valid key every request answers 401, and every response carries
X-Robots-Tag: noindex, nofollow, noarchive. Your domain is the only public copy. - Caching: responses are
Cache-Control: private, max-age=60with anETag; sendIf-None-Matchto get304. Cache on your side and refresh on our webhook. - Limits: 20 requests a second per key (bursts of 200), then
429withRetry-After. - Errors:
401wrong or revoked key;404no such file (a post that does not exist);429slow down.
Serving a request
For every path under your blog, in this order:
- Redirects first. If the path is in
redirects.json, answer301toto, or410whentois null. - The page. If
posts/{slug}.jsonexists and itspathis the request path, render it. - Otherwise a real
404, never a200page that says "not found".
Render on the server:
<title>fromseo.title;head_htmlin the<head>, removing your own description, canonical, Open Graph and Article JSON-LD so nothing is duplicated;- the title as the only
<h1>; - then
html.
Files
site.json (json)
The site: name, routes, feed, structured data.
| Field | Type | Meaning |
|---|---|---|
name |
string |
The site's name (as in og:site_name and structured data) |
url |
string |
The site's home URL |
language |
string |
Default content language |
description |
string | null |
What the site is about |
logo |
string | null |
Logo URL |
routes |
{ index, post, author, topic } |
Where each kind of page lives, e.g. post: "/blog/{slug}" |
feed |
string |
The RSS feed URL to serve |
json_ld |
object |
Organization and WebSite structured data, for your home page |
posts/index.json (json)
Published pages, newest first, 100 per file: { page, pages, total, next, posts: [summary] }. Follow next (posts/index-2.json...).
| Field | Type | Meaning |
|---|---|---|
id |
string |
Stable id of the page |
collection |
"blog" | "pages" |
Blog post, or a service/SaaS/product page |
slug |
string |
The public slug |
path |
string |
The exact path to serve it at, e.g. /blog/my-post (no trailing slash) |
url |
string |
The canonical URL on your domain |
title |
string |
Title, rendered as the page's only |
summary |
string | null |
One or two sentences: the meta description and the answer first |
feature_image |
{ url, alt, width, height, srcset, credit: { name, url, source } } | null |
Feature image, with dimensions and srcset; show the credit when present |
author |
{ slug, name, url } | null |
The byline's author |
topics |
Array<{ slug, name, url }> |
Topic (cluster) the post belongs to |
reading_time |
number |
Minutes |
published_at |
ISO 8601 |
First publish date (datePublished) |
updated_at |
ISO 8601 |
Last change to the content (dateModified, sitemap lastmod) |
posts/{slug}.json (json)
One page with everything to render it.
| Field | Type | Meaning |
|---|---|---|
id |
string |
Stable id of the page |
collection |
"blog" | "pages" |
Blog post, or a service/SaaS/product page |
slug |
string |
The public slug |
path |
string |
The exact path to serve it at, e.g. /blog/my-post (no trailing slash) |
url |
string |
The canonical URL on your domain |
title |
string |
Title, rendered as the page's only |
summary |
string | null |
One or two sentences: the meta description and the answer first |
feature_image |
{ url, alt, width, height, srcset, credit: { name, url, source } } | null |
Feature image, with dimensions and srcset; show the credit when present |
author |
{ slug, name, url } | null |
The byline's author |
topics |
Array<{ slug, name, url }> |
Topic (cluster) the post belongs to |
reading_time |
number |
Minutes |
published_at |
ISO 8601 |
First publish date (datePublished) |
updated_at |
ISO 8601 |
Last change to the content (dateModified, sitemap lastmod) |
html |
string |
The body: no , headings with ids, byline, calls to action and footer included. Render it as is, on the server |
markdown |
string |
The same body as markdown (for /blog/{slug}.md or other renderers) |
toc |
Array<{ id, text, level }> |
Table of contents from the h2/h3 headings |
word_count |
number |
Words in the body |
language |
string |
Content language, for |
version |
number |
Increases with every content change |
content_hash |
string |
Changes when the content changes |
seo |
{ title, description, canonical, robots, og, twitter } |
Everything for the , as fields |
json_ld |
object |
Structured data (@graph: Organization, WebSite, WebPage, BlogPosting, Person, BreadcrumbList, FAQPage...) |
head_html |
string |
Ready-made tags: description, canonical, robots, Open Graph, Twitter and the JSON-LD. Not the |
breadcrumbs |
Array<{ name, url }> |
Home > Blog > Post |
related |
Array<summary> |
Related posts (same topic first) |
alternates |
Array<{ hreflang, url }> |
Other languages of the page (empty until translations exist) |
authors/index.json (json)
Authors: { authors: [{ slug, name, url, job_title, posts }] }.
authors/{slug}.json (json)
An author page: name, job_title, bio, image, profiles, posts, seo, json_ld (ProfilePage), head_html.
topics/index.json (json)
Topics: { topics: [{ slug, name, url, posts, indexable }] }.
topics/{slug}.json (json)
A topic page: name, posts, seo (noindex under 3 posts), json_ld (CollectionPage), head_html.
redirects.json (json)
{ redirects: [{ from, to, status }] }: answer 301 to to, or 410 when to is null, before rendering anything.
sitemap.xml (xml)
Indexable URLs only, honest lastmod, image entries. Serve at /sitemap.xml or merge into yours.
feed.xml (xml)
RSS 2.0, newest 50 posts. Serve at site.feed.
llms.txt (text)
For AI search engines. Serve at /llms.txt.
search.json (json)
For on-site search: { entries: [{ title, summary, url, topics }] }.
changes.json (json)
What changed, newest first: { cursor, changes: [{ id, event, path, url, version, at }] }. For incremental builds and missed webhooks.
indexnow.txt (text)
The site's IndexNow key: serve it as text at /{key}.txt.