Content Studio delivery API reference
Every endpoint, field, error and limit of the Content Studio delivery API: resolve and list published pages, sanitized HTML, assets, sitemaps, llms.txt and draft previews.
This is the complete reference for reading published Content Studio content from your own website, app or build pipeline. It is plain HTTPS and JSON, so it works from any language, any framework and any server, and from the browser on any domain. For step-by-step code for specific stacks, see connecting Content Studio to your website or app.
Base URL
Every public URL for one content space starts with:
https://axisiq.co/content/{orgID}/{bucketKey}
{orgID}is your organisation's ID.{bucketKey}is the key you gave the content space when you created it, such aswebsiteordocs.
You do not have to assemble these by hand. In Content Studio, open the space's settings (the gear next to its name in the left rail). The Delivery API & discovery section lists your exact URLs; click one to copy it.
Before anything answers: open the space to the public
A new content space is private, and every public URL returns 404 until you grant access. To grant it:
- Go to Team & Permissions → Roles and create a role from the Public visitors template. Only the organisation owner can make a role apply to visitors who are not signed in.
- Make sure Published pages is set to Readable by anyone. This covers your pages, your uploaded images and the generated discovery files.
- Save the role. Your delivery URLs answer straight away.
Only published documents are ever served. Drafts, unpublished pages and edits made since the last publish never appear on the public API.
Endpoints
| Method and path | Returns |
|---|---|
GET /resolve?path={path} |
One published document, including its body as markdown and as HTML |
GET /list?prefix={folder}&tag={tag} |
Summaries of published documents, newest first |
GET /render/{path} |
The same document as a complete, unstyled HTML page |
GET /sitemap.xml |
Sitemap of every published, indexable page |
GET /robots.txt |
Allows crawling and names the sitemap |
GET /llms.txt |
Index of the site for AI models, following llmstxt.org |
GET /llms-full.txt |
The same index with every page's text inlined |
GET https://axisiq.co/content/{orgID}/assets/{key} |
An uploaded image or file |
All endpoints are read-only GET requests and need no key.
Resolve a URL to a document
GET /content/{orgID}/{bucketKey}/resolve?path=blog/2026/warehouse-move
path is the document's path, which is also its URL on your site. Leading and trailing slashes are ignored, so /blog/2026/warehouse-move/ works too. An empty path returns the document at the space's root, which is usually your homepage.
{
"data": {
"path": "blog/2026/warehouse-move",
"title": "We moved the warehouse in a weekend",
"body": "Markdown source of the page…",
"html": "<p>The same body, rendered to HTML…</p>",
"seo": {
"title": "Moving a warehouse in 48 hours",
"description": "How we moved 4,000 SKUs without missing an order.",
"keywords": ["warehouse", "operations"],
"og_image": "https://axisiq.co/content/{orgID}/assets/2026/09/a1b2c3d4-hero.webp"
},
"tags": ["operations", "stories"],
"published_at": "2026-09-30T10:12:00Z"
}
}
| Field | Notes |
|---|---|
path |
The routing key. Unique within the space. |
title |
The document title, for your <h1>. |
body |
Markdown, with GitHub-flavoured extensions such as tables, task lists and strikethrough. |
html |
The body already rendered to HTML. See Using the HTML. |
seo |
Meta fields for your <head>: title, description, keywords, canonical_url, og_title, og_description, og_image and noindex. Fields that are empty are left out of the JSON, so fall back to title when seo.title is missing. |
tags |
Lower-case, free-form labels. Always an array. |
published_at |
When this version was published (RFC 3339, UTC). |
List a folder
GET /content/{orgID}/{bucketKey}/list?prefix=blog/&tag=stories
Both parameters are optional. prefix limits the list to paths that start with it, so blog/ returns everything under the blog folder at any depth. tag returns only documents carrying that tag.
{
"data": {
"documents": [
{
"path": "blog/2026/warehouse-move",
"title": "We moved the warehouse in a weekend",
"seo": { "description": "How we moved 4,000 SKUs without missing an order." },
"tags": ["operations", "stories"],
"published_at": "2026-09-30T10:12:00Z"
}
]
}
}
List results are summaries: they have no body or html, so an index page stays small. Fetch a single page's content with resolve. Documents come newest-published first. The list is not paginated; it returns every match, so page through it on your side when a folder grows large.
Render a page as HTML
GET /content/{orgID}/{bucketKey}/render/blog/2026/warehouse-move
This returns a complete HTML document for the page: the <head> filled from its SEO block, including Open Graph tags and schema.org structured data, a plain navigation header, the article, and a footer. It has no styling and no branding, because your design belongs to your site. It exists for readers that do not run JavaScript, such as AI crawlers and link-preview bots. An unknown path returns a real 404 HTML page, not an empty 200.
Discovery files
sitemap.xml, robots.txt, llms.txt and llms-full.txt are generated on every request from what is published at that moment, so a page you publish appears in them immediately. Pages with the noindex switch on are left out of all four.
Links inside them use the space's Site URL setting. If you have not set one, they use the address the request arrived on. Serve the files from your own domain by forwarding those four paths to AxisIQ, for example https://example.com/sitemap.xml to https://axisiq.co/content/{orgID}/{bucketKey}/sitemap.xml.
Images and files
Images you upload in the editor are served from https://axisiq.co/content/{orgID}/assets/{key}. The API returns these as absolute URLs in body, html and seo.og_image, so they load correctly on any domain. Responses carry an ETag, so browsers and CDNs revalidate cheaply. Images, PDFs, plain text, MP3 and MP4 display inline. Every other file type, including SVG and HTML, downloads as an attachment for security.
Using the HTML
The html field saves you a markdown library. It is safe to insert into your page:
- Raw HTML written inside a document is escaped and shown as text. It is never output as markup.
- Links and images that use anything other than
http,https,mailtoor a relative address are removed, sojavascript:anddata:URLs cannot reach your visitors. - Headings get
idattributes, so you can link to a section or build a table of contents.
The HTML has no classes or inline styles. Style it with your own CSS, for example by wrapping it in an element with a prose class.
If you prefer to render the markdown yourself, use body instead. It is the source the editor saves and follows standard markdown with GitHub extensions. Most markdown libraries support it, including marked, markdown-it, react-markdown, remark, goldmark, Python-Markdown, commonmarker and league/commonmark.
Errors
Every failure returns 404 with the standard error shape:
{ "error": { "code": "NOT_FOUND", "message": "not found", "request_id": "…" } }
A missing page, an unpublished page, an unknown space and a space that is not open to the public all look the same. This is deliberate: a public URL never reveals what exists. If a page you expect is missing, check that it is published and that the Public visitors role grants Published pages.
Going over the rate limit returns 429 with code RATE_LIMITED.
A 403 with an HTML body comes from the network edge, not the API. It means the request looked like an automated scanner. This happens with clients that send a generic default User-Agent, such as Python's urllib. Send a User-Agent header that names your site, for example example.com-site/1.0.
Caching and limits
| Response | Cache-Control |
|---|---|
resolve, list |
public, max-age=60 |
| Discovery files | public, max-age=300 |
| Images and files | public, max-age=3600, with ETag |
render |
no-cache |
Each IP address can make 240 requests a minute to the delivery API. A browser fetching a few pages will never notice. A server that renders pages on request sends all its visitors' requests from one address, so it should cache responses. Every framework example in the integration guide caches for 60 seconds, which matches the API's own cache lifetime. A CDN in front of your site does the same job.
Cross-origin requests
The delivery API answers browser requests from any origin (Access-Control-Allow-Origin: *). A plain HTML page, a React or Vue app, or a widget on someone else's site can call it with fetch and no proxy. No cookies or credentials are involved.
Reading drafts privately
The public API only ever serves published content. To preview drafts on a staging site, or to read content from a backend that should not depend on public access, use the authenticated management API with an access key:
- In Team & Permissions → Access keys, create a service account and give it a role with Website content: Can view. To limit it to one content space, open the role's Advanced editor and name that space's key as the resource.
- Create a key for the service account. It starts with
axk_and is shown once, so store it as a server-side secret. - Call the management API with the key as a bearer token:
GET https://axisiq.co/api/v1/orgs/{orgID}/content/buckets
GET https://axisiq.co/api/v1/orgs/{orgID}/content/buckets/{bucketID}/documents?prefix=blog/&status=draft
GET https://axisiq.co/api/v1/orgs/{orgID}/content/documents/{documentID}
Authorization: Bearer axk_…
The first call returns your spaces with their IDs. The document list accepts prefix, status (draft or published), tag and q (search). Fetching a single document returns its current draft title, body, seo and tags, along with status and an edited flag showing whether the draft has moved ahead of what is live.
Never send an access key to a browser. The management API only accepts requests from AxisIQ's own web app, so call it from your server or build step.
What is not available yet
- No publish webhook. A static site that fetches content at build time will not rebuild by itself when you publish. Rebuild on a schedule, or rebuild from your CI when you publish. The integration guide shows both.
- No version history or scheduled publishing. Publishing replaces the live version immediately.
- No pagination on
list. - Markdown bodies only. There are no structured content models (custom fields per document type) yet. Use tags and folders to organise content, and the SEO block for metadata.