The Delivery API returns published content as JSON. It is read-only, cached at the edge and safe to call on every request.
https://api.manifolio.com/delivery/v1/{projectId}/
Authorization: Bearer mf_live_your_secret_keyprojectId is the project's id (a UUID), shown under Developers → API keys → Connection. The key must belong to the same project and have the content:read scope.
Endpoints
| Path | Returns |
|---|---|
GET /types | the project's languages and its types with their fields |
GET /entries/{type} | published entries of a collection, one page at a time |
GET /entries/{type}/{idOrSlug} | one entry, by id or by slug in the requested language |
GET /singletons/{type} | the entry of a singleton type |
Parameters
| Parameter | Example | Meaning |
|---|---|---|
locale | ro | language of the response; untranslated fields fall back to the main language |
fields | title,slug,date | only these fields; _id, _type, _locale, _publishedAt and _updatedAt always come |
filter[field] | filter[series]=har | equals, on top-level fields |
filter[field][op] | filter[date][gte]=2026-01-01 | eq, ne, gt, gte, lt, lte, in (comma list), exists (true or false) |
sort | -date | published, updated or a field; - for descending. Default -published |
limit | 20 | 1 to 100, default 20 |
cursor | from nextCursor | the next page; a cursor only works with the sort it came from |
populate | 1 | 0 to 3: references become full entries, up to that depth |
filter, sort, limit and cursor apply to lists; a single entry or a singleton accepts locale, fields and populate.
Examples
curl -H "Authorization: Bearer $MANIFOLIO_KEY" \
"https://api.manifolio.com/delivery/v1/$PROJECT/entries/article?locale=ro&fields=title,slug,author&populate=1&limit=10"
curl -H "Authorization: Bearer $MANIFOLIO_KEY" \
"https://api.manifolio.com/delivery/v1/$PROJECT/entries/event?filter[startsAt][gte]=2026-10-01&sort=startsAt"
curl -H "Authorization: Bearer $MANIFOLIO_KEY" \
"https://api.manifolio.com/delivery/v1/$PROJECT/singletons/site_settings"Responses
A list:
{
"entries": [
{ "_id": "01a1b2c3-0000-7000-8000-000000000001", "_type": "article", "_locale": "ro",
"_publishedAt": "2026-10-12T09:00:00.000Z", "_updatedAt": "2026-10-12T08:55:00.000Z",
"title": "Primul articol", "slug": "primul-articol" }
],
"nextCursor": "eyJ2IjoxfQ"
}One entry or a singleton:
{ "entry": { "_id": "01a1b2c3-0000-7000-8000-000000000001", "_type": "article", "title": "Primul articol" } }A reference is the target's id until you ask for populate. A reference to an entry that is not published is left out.
Errors
Errors have one shape: { "error": { "code": "missing_scope", "message": "This key needs the content:read scope." } }.
| Status | Codes |
|---|---|
| 400 | invalid_locale, invalid_limit, invalid_fields, invalid_sort, invalid_populate, invalid_filter, invalid_cursor |
| 401 | missing_key, invalid_key, key_revoked |
| 403 | publishable_key, missing_scope |
| 404 | project_not_found, type_not_found, entry_not_found |
Caching
- Responses are cached at the edge under a key that includes the project's content version. Publishing, unpublishing, deleting or changing a type bumps the version, so a published change is visible on the next request. The
x-cacheheader saysHITorMISS. - Every response has an
ETag; send it back inIf-None-Matchto get304 Not Modified. - For your own clients the API sends
Cache-Control: private, max-age=0, must-revalidate.
Preview API
The same paths under /preview/v1/{projectId}/ return the latest saved version of every entry, drafts included. Use a key with the content:preview scope (development keys have it by default). Preview responses are never cached and each entry also carries _status: draft, published or changed.