Delivery API
Base URL: https://api.avvyr.com/v1/content/{siteId}. Every request needs the site's key in x-cms-key (or ?key=). See Keys and access.
Versions and caching
Every publish raises the site's version. Content is read under a version, /v/{version}/{locale}/..., and those responses never change: they are sent with Cache-Control: public, max-age=31536000, immutable.
GET /version
# { "version": 42, "locales": ["sv", "en"], "defaultLocale": "sv" } max-age=5
GET /v/42/sv/pages/om-oss
Ask for /version first, then read under that version. If you ask for an old version, the API answers 302 to the same URL with the current version. The version is a cache key, not an archive.
Nothing needs purging when content is published: the next /version points at new URLs. @avvyr/cms and @avvyr/cms-nuxt do this for you.
Endpoints
| Method | Path | Returns |
|---|---|---|
| GET | /version | { version, locales, defaultLocale } |
| GET | /v/{version}/{locale}/pages | The home page document |
| GET | /v/{version}/{locale}/pages/{path} | The document at that path, e.g. pages/blogg/var-nya-soffa |
| GET | /v/{version}/{locale}/entries/{entryId} | One document by id |
| GET | /v/{version}/{locale}/entries | { data, total }, see Listing entries |
| GET | /v/{version}/{locale}/singletons/{type} | The singleton's document, e.g. singletons/navigation |
| GET | /v/{version}/{locale}/manifest | Every published entry and folder, without fields |
| GET | /v/{version}/{locale}/bundle | { manifest, documents }: the whole site in one response |
| GET | /changes?from=&to= | What changed between two versions |
| GET | /{locale}/search?q=&type=&limit= | { data: ManifestEntry[] }, max-age 30 s |
| GET | /draft/{locale}/pages/{path}, /draft/{locale}/entries/{entryId} | Drafts, see Preview |
A path or id that is not published returns 404.
Documents
type ManifestEntry = {
id: string
type: string // the entry type's key
title: string
path: string | null // null for types that are not routable
folderId: string | null
order: number
publishedAt: string
firstPublishedAt: string
alternates: Record<string, string | null> // the path in each other language
list: Record<string, unknown> // the type's listFields
}
type Document = ManifestEntry & {
locale: string
fields: Record<string, unknown> // published values, see Types and fields
}
alternates gives you hreflang links. list holds the type's listFields, enough to render cards and menus without fetching each document.
Listing entries
GET /v/42/sv/entries?type=article&sort=-publishedAt&limit=10
GET /v/42/sv/entries?folder={folderId}&deep=1
GET /v/42/sv/entries?ids=a,b,c&include=documents
| Parameter | |
|---|---|
type | Entry type key |
folder | Folder id, or root for the top level |
deep | 1 includes subfolders |
ids | Comma-separated ids; the order is kept |
sort | order (default), title, publishedAt, -publishedAt, firstPublishedAt, -firstPublishedAt |
limit, offset | Default 100, max 1000 |
include | documents returns full documents instead of manifest rows |
Syncing a whole site
For a site that keeps content in memory or in its own store:
- At startup, load
/v/{version}/{locale}/bundlefor each language. - Poll
/versionevery few seconds. It is cached for 5 seconds and cheap. - When the version moves, call
/changes?from={old}&to={new}. It returns{ changed, removed, structure, complete }: entry ids to refetch and ids to drop.structure: truemeans paths or folders changed, so reload the manifest. - If
completeisfalse, the history does not cover the range. Load the bundle again.
Change history is kept for 90 days. @avvyr/cms-nuxt implements exactly this.
Search
GET /{locale}/search?q=sofa&type=article&limit=5 searches titles and list fields of published entries. The default limit is 20 and the max is 100. It is meant for a site search box, not as a full-text engine.