# Items · Content Delivery API

> Content Delivery API reference for items: GET /collections/{key}/items, GET /collections/{key}/items/{slug}.

> Markdown version of https://kanorio.com/en/developers/delivery-api/items. Append `.md` to any developer docs URL for this format. Index: https://kanorio.com/llms.txt · MCP: https://app.kanorio.com/api/mcp

Base URL: `https://{site}/api/v1` · [Errors](https://kanorio.com/en/developers/basics/errors) · [Pagination](https://kanorio.com/en/developers/basics/pagination)

### Published items of a collection

`GET /collections/{key}/items`

- Stability: beta
- Authentication: none

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `key` | path | string | yes | — |
| `filter` | query | object | no | Bracket-notation filter conditions (up to 10 conditions combined with AND, plus 2-level OR groups via filter[any][0][field][op]=value). Shorthand filter[field]=value equals filter[field][eq]=value. 15 operators by field type: eq, ne, in, nin (up to 100 comma-separated values), gt, gte, lt, lte, contains, ncontains, match (multi-word substring match on text/rich_text, max 1 per query and 8 words), exists (true\|false), has (multi_select/multi_reference), eq_slug (reference), has_slug (multi_reference). Item-level attributes slug, publishedAt, createdAt, updatedAt are also filterable. Date/datetime fields accept relative expressions: now or now[+-]<N><s\|m\|h\|d\|w\|M\|y> (e.g. filter[publishedAt][gte]=now-30d). |
| `sort` | query | string | no | Comma-separated sort fields (up to 3 fields), prefix with `-` for descending (e.g. `sort=-publishedAt,title`), or bracket form `sort[field]=asc\|desc`. Sortable: scalar fields and item attributes (`slug`, `publishedAt`, `createdAt`, `updatedAt`); `rich_text`, `json`, `image`, `gallery`, `file`, and `multi_*` are not sortable. |
| `limit` | query | integer | no | Maximum number of items to return, 1-100. Defaults to 20. |
| `cursor` | query | string | no | Opaque cursor from the previous page's nextCursor. Omit for the first page. |
| `total` | query | boolean | no | true adds total (the number of matching items) to the response; it costs an extra count query. |
| `fields` | query | string | no | Comma-separated `fieldData` field IDs to project (top-level item metadata `id`, `slug`, `publishedAt`, `updatedAt` are always returned). |
| `expand` | query | string | no | Comma-separated `reference` or `multi_reference` field IDs (plus `primary_author`, `primary_category` on `blog`) to expand 1 layer into `item.expanded[fieldId]`. Referenced media assets are automatically included in the top-level `assets` map (trashed, missing, or private-bucket assets are filtered out). |
| `includeDepth` | query | 1 | no | Reference include depth. Only 1 is accepted in v1. |
| `formats` | query | string | no | Comma-separated blog content formats: markdown, html, plaintext |
| `locale` | query | string | no | Locale for item fields marked localized; for the blog, blog_categories, blog_tags and authors collections, the post, category, tag and author translations (titles, excerpts, bodies, SEO fields). Expanded references are translated too. One of the site's locales from /site (a code such as `en-US` or the URL prefix such as `en`); omit it for the primary locale. Other values, including locales that are still translating, return 400 UNSUPPORTED_LOCALE. Untranslated fields fall back to the primary locale. On multilingual sites each item carries resolvedLocale and availableLocales. |
| `preview` | query | "1" | no | Pass `preview=1` with `X-Kanorio-Preview: knr_pv_<token>` (or a server-held PAT with `collections:view`) to read unpublished draft `fieldData` (`Cache-Control: no-store`). |

**Response** (200)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `data` | object[] | yes | — |
| `hasMore` | boolean | yes | True when another page exists; pass nextCursor to fetch it. |
| `nextCursor` | string \| null | yes | Cursor for the next page, or null on the last page. |
| `total` | integer | no | Number of matching items; only present when the request sets total=true. |
| `assets` | object | yes | — |
| `access` | object | no | Field-level access summary. At the top level it describes the collection policy for the current viewer (anonymous or the bearer of a Customer Access Token); per-item access may differ when the collection sets itemOverrideField, so render per item from items[].access. |
| `access.granted` | boolean | yes | — |
| `access.gated` | string[] | yes | — |
| `access.requires` | object \| null | yes | — |
| `access.requires.kind` | "customer" \| "entitlement" | no | — |
| `access.requires.featureKey` | string | no | — |

**Errors**

| Code | Status | When |
| --- | --- | --- |
| `COLLECTION_NOT_FOUND` | 404 | — |
| `INVALID_QUERY` | 400 | — |
| `INVALID_CURSOR` | 400 | — |
| `UNSUPPORTED_LOCALE` | 400 | — |
| `QUERY_TIMEOUT` | 503 | — |

```bash
curl -X GET "https://{site}/api/v1/collections/{key}/items"
```

### One published item by slug

`GET /collections/{key}/items/{slug}`

- Stability: beta
- Authentication: none

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `key` | path | string | yes | — |
| `slug` | path | string | yes | — |
| `fields` | query | string | no | — |
| `expand` | query | string | no | — |
| `formats` | query | string | no | Comma-separated blog content formats: markdown, html, plaintext |
| `preview` | query | "1" | no | — |
| `includeDepth` | query | 1 | no | Reference include depth. Only 1 is accepted in v1. |
| `locale` | query | string | no | Locale for the item, the same as the list endpoint (system collections use the post, category, tag and author translations; expanded references are translated too). One of the site's locales from /site (a code such as `en-US` or the URL prefix such as `en`); omit it for the primary locale. Other values, including locales that are still translating, return 400 UNSUPPORTED_LOCALE. Untranslated fields fall back to the primary locale. On multilingual sites the item carries resolvedLocale and availableLocales. |

**Response** (200)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `item` | object | yes | — |
| `assets` | object | yes | — |
| `access` | object | no | Field-level access summary. At the top level it describes the collection policy for the current viewer (anonymous or the bearer of a Customer Access Token); per-item access may differ when the collection sets itemOverrideField, so render per item from items[].access. |
| `access.granted` | boolean | yes | — |
| `access.gated` | string[] | yes | — |
| `access.requires` | object \| null | yes | — |
| `access.requires.kind` | "customer" \| "entitlement" | no | — |
| `access.requires.featureKey` | string | no | — |

**Errors**

| Code | Status | When |
| --- | --- | --- |
| `COLLECTION_NOT_FOUND` | 404 | — |
| `ITEM_NOT_FOUND` | 404 | — |
| `UNSUPPORTED_LOCALE` | 400 | — |

```bash
curl -X GET "https://{site}/api/v1/collections/{key}/items/{slug}"
```
