# API reference: Content

> Every content endpoint: what it takes, what it answers with, and which key it needs.

## List every page's draft

`GET /api/v1/content/drafts` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `locale` | string |  | Filter by language, for example `de`. |
| `page` | integer |  |  |
| `page_size` | integer |  |  |

Answers `200` with [PaginatedDraftSummaryList](#paginateddraftsummarylist).

## Create a page as a draft

`POST /api/v1/content/drafts` · Secret key only · needs an `Idempotency-Key`

| Field | Type | Required | |
|---|---|---|---|
| `title` | string | yes |  |
| `slug` | string or empty |  | Made from the title when left out or empty. |
| `locale` | string |  | One of the schema's `locales`. The default language when left out. |
| `sections` | list of [SectionRequest](#sectionrequest) |  | The page's sections, in order, each fitting its section type. |
| `meta` | [PageMetaRequest](#pagemetarequest) |  |  |

Answers `201` with [Draft](#draft).

## Fetch one page's draft

`GET /api/v1/content/drafts/{page_id}` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `page_id` | uuid | yes |  |

Answers `200` with [Draft](#draft).

## Change a page's draft

`POST /api/v1/content/drafts/{page_id}` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `page_id` | uuid | yes |  |

| Field | Type | Required | |
|---|---|---|---|
| `title` | string |  |  |
| `slug` | string or empty |  | Made from the title when left out or empty. |
| `locale` | string |  | One of the schema's `locales`. The default language when left out. |
| `sections` | list of [SectionRequest](#sectionrequest) |  | Replaces every section the draft holds, so send the ones left as they were too. |
| `meta` | [PageMetaRequest](#pagemetarequest) |  |  |

Answers `200` with [Draft](#draft).

## Delete a page

`POST /api/v1/content/drafts/{page_id}/delete` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `page_id` | uuid | yes |  |

Answers `200` with [DeletedPage](#deletedpage).

## Publish a page

`POST /api/v1/content/drafts/{page_id}/publish` · Secret key only · needs an `Idempotency-Key`

| Parameter | Type | Required | |
|---|---|---|---|
| `page_id` | uuid | yes |  |

Answers `200` with [Draft](#draft).

## Publish an earlier version again

`POST /api/v1/content/drafts/{page_id}/restore` · Secret key only · needs an `Idempotency-Key`

| Parameter | Type | Required | |
|---|---|---|---|
| `page_id` | uuid | yes |  |

| Field | Type | Required | |
|---|---|---|---|
| `version` | integer | yes | The number of the version to publish again. |

Answers `200` with [Draft](#draft).

## Take a page off the website

`POST /api/v1/content/drafts/{page_id}/unpublish` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `page_id` | uuid | yes |  |

Answers `200` with [Draft](#draft).

## List a page's published versions

`GET /api/v1/content/drafts/{page_id}/versions` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `page` | integer |  |  |
| `page_id` | uuid | yes |  |
| `page_size` | integer |  |  |

Answers `200` with [PaginatedPageVersionList](#paginatedpageversionlist).

## Cheap poll for change detection

`GET /api/v1/content/manifest` · Any key

Answers `200` with [ContentManifest](#contentmanifest).

## List published pages

`GET /api/v1/content/pages` · Any key

| Parameter | Type | Required | |
|---|---|---|---|
| `locale` | string |  | Filter by language, for example `de`. |
| `page` | integer |  |  |
| `page_size` | integer |  |  |

Answers `200` with [PaginatedPageSummaryList](#paginatedpagesummarylist).

## Fetch one published page

`GET /api/v1/content/pages/{slug}` · Any key

| Parameter | Type | Required | |
|---|---|---|---|
| `locale` | string |  |  |
| `slug` | string | yes |  |

Answers `200` with [PageDetail](#pagedetail).

## Fetch the content schema

`GET /api/v1/content/schema` · Secret key only

Answers `200` with [ContentSchema](#contentschema).

## Add a section type

`POST /api/v1/content/section-types` · Secret key only · needs an `Idempotency-Key`

| Field | Type | Required | |
|---|---|---|---|
| `key` | string | yes | What a section of this type carries as its `type`: letters, digits and underscores, starting with a letter. Permanent. |
| `label` | string | yes | What the editor calls it. |
| `help_text` | string |  |  |
| `max_per_page` | integer or null |  | Null or left out for any number. |
| `active` | boolean |  | Whether the editor offers it. True when left out. |
| `fields` | list of [SectionFieldRequestRequest](#sectionfieldrequestrequest) |  | Its fields, in order. One refused makes nothing at all. |

Answers `201` with [SectionType](#sectiontype).

## Change a section type

`POST /api/v1/content/section-types/{type_id}` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `type_id` | uuid | yes |  |

| Field | Type | Required | |
|---|---|---|---|
| `key` | string |  | Permanent: a different key is refused. |
| `label` | string |  |  |
| `help_text` | string |  |  |
| `max_per_page` | integer or null |  | Null for any number. |
| `active` | boolean |  | Off stops the editor offering it. Pages already holding one keep it. |

Answers `200` with [SectionType](#sectiontype).

## Remove a section type

`POST /api/v1/content/section-types/{type_id}/delete` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `type_id` | uuid | yes |  |

Answers `200` with [DeletedSectionType](#deletedsectiontype).

## Add a field to a section type

`POST /api/v1/content/section-types/{type_id}/fields` · Secret key only · needs an `Idempotency-Key`

| Parameter | Type | Required | |
|---|---|---|---|
| `type_id` | uuid | yes |  |

| Field | Type | Required | |
|---|---|---|---|
| `key` | string | yes | The property a section carries this field's value under: letters, digits and underscores, starting with a letter. Permanent. |
| `kind` | [SectionFieldKindEnum](#sectionfieldkindenum) |  | `text` when left out. * `text` - text * `long` - long * `list` - list * `link` - link * `flag` - flag * `items` - items * `image` - image |
| `label` | string | yes | What the editor calls it. |
| `help_text` | string |  |  |
| `required` | boolean |  | Whether a published page may leave it empty. |
| `item_label` | string |  | For `items` only: what one entry is called. |
| `item_fields` | list of [RowFieldRequestRequest](#rowfieldrequestrequest) |  | For `items` only, and required by it: the fields of each entry, one level deep. |

Answers `201` with [SectionType](#sectiontype).

## Change a field

`POST /api/v1/content/section-types/{type_id}/fields/{field_id}` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `field_id` | uuid | yes |  |
| `type_id` | uuid | yes |  |

| Field | Type | Required | |
|---|---|---|---|
| `key` | string |  | Permanent: a different key is refused. |
| `kind` | [SectionFieldKindEnum](#sectionfieldkindenum) |  | What a page already holds under it is checked against the new kind when that page is next saved. * `text` - text * `long` - long * `list` - list * `link` - link * `flag` - flag * `items` - items * `image` - image |
| `label` | string |  |  |
| `help_text` | string |  |  |
| `required` | boolean |  |  |
| `item_label` | string |  |  |
| `item_fields` | list of [RowFieldRequestRequest](#rowfieldrequestrequest) |  | Replaces every row field the group has. |

Answers `200` with [SectionType](#sectiontype).

## Remove a field

`POST /api/v1/content/section-types/{type_id}/fields/{field_id}/delete` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `field_id` | uuid | yes |  |
| `type_id` | uuid | yes |  |

Answers `200` with [SectionType](#sectiontype).

## List the image library

`GET /api/v1/images` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `page` | integer |  |  |
| `page_size` | integer |  |  |

Answers `200` with [PaginatedImageList](#paginatedimagelist).

## Fetch one library image

`GET /api/v1/images/{image_id}` · Secret key only

| Parameter | Type | Required | |
|---|---|---|---|
| `image_id` | uuid | yes |  |

Answers `200` with [Image](#image).

## Shapes

### PaginatedDraftSummaryList

| Field | Type | Always there | |
|---|---|---|---|
| `count` | integer | yes |  |
| `results` | list of [DraftSummary](#draftsummary) | yes |  |

### Draft

| Field | Type | Always there | |
|---|---|---|---|
| `id` | uuid | yes |  |
| `slug` | string | yes |  |
| `locale` | string | yes |  |
| `title` | string | yes | The draft's title, which the website shows once it is published. |
| `status` | [StatusEnum](#statusenum) | yes |  |
| `live_version` | integer or null | yes | The number of the version the website shows. Null while nothing is published. |
| `changed` | boolean | yes | Whether the draft holds edits the website does not show yet. False while nothing is published. |
| `updated_at` | date-time | yes |  |
| `sections` | list of [Section](#section) | yes |  |
| `meta` | object | yes |  |
| `published_at` | date-time or null | yes | When the version the website shows was published. Null while nothing is. |

### DeletedPage

| Field | Type | Always there | |
|---|---|---|---|
| `id` | uuid | yes |  |
| `deleted` | boolean | yes |  |

### PaginatedPageVersionList

| Field | Type | Always there | |
|---|---|---|---|
| `count` | integer | yes |  |
| `results` | list of [PageVersion](#pageversion) | yes |  |

### ContentManifest

| Field | Type | Always there | |
|---|---|---|---|
| `cache_version` | integer | yes | Changes on every publish, and with a test key on every draft saved. Poll this rather than refetching pages. |
| `page_count` | integer | yes |  |
| `locales` | list of string | yes | Languages something is actually published in, or with a test key has a draft in. |
| `configured_locales` | list of string | yes | Languages this project is set up to publish in. |
| `default_locale` | string | yes |  |

### PaginatedPageSummaryList

| Field | Type | Always there | |
|---|---|---|---|
| `count` | integer | yes |  |
| `results` | list of [PageSummary](#pagesummary) | yes |  |

### PageDetail

| Field | Type | Always there | |
|---|---|---|---|
| `slug` | string | yes |  |
| `locale` | string | yes |  |
| `title` | string | yes |  |
| `updated_at` | date-time | yes |  |
| `version` | integer or null | yes | The live version's number. Null for a test key's draft never published. |
| `sections` | list of [Section](#section) | yes |  |
| `meta` | object | yes |  |
| `published_at` | date-time or null | yes | When the live version was published. Null for a test key's draft never published. |
| `translations` | list of string | yes |  |

### ContentSchema

| Field | Type | Always there | |
|---|---|---|---|
| `default_locale` | string | yes |  |
| `locales` | list of string | yes | Every language a page may be in. |
| `section_types` | list of [SectionType](#sectiontype) | yes |  |

### SectionType

| Field | Type | Always there | |
|---|---|---|---|
| `id` | uuid | yes |  |
| `key` | string | yes | What a section of this type carries as its `type`. |
| `label` | string | yes |  |
| `help_text` | string | yes |  |
| `max_per_page` | integer or null | yes | How many one page may hold. Null for any number. |
| `active` | boolean | yes | Whether the editor offers it. A retired type stays on the pages using it. |
| `fields` | list of [SectionField](#sectionfield) | yes |  |

### DeletedSectionType

| Field | Type | Always there | |
|---|---|---|---|
| `id` | uuid | yes |  |
| `deleted` | boolean | yes |  |

### PaginatedImageList

| Field | Type | Always there | |
|---|---|---|---|
| `count` | integer | yes |  |
| `results` | list of [Image](#image) | yes |  |

### Image

| Field | Type | Always there | |
|---|---|---|---|
| `id` | uuid | yes | What an image field of a page is given to show this image. |
| `url` | uri | yes | Where the image is, public to anybody holding the address. |
| `width` | integer | yes |  |
| `height` | integer | yes |  |
| `alt` | string | yes | What the picture shows, for somebody who cannot see it. May be empty. |
| `created_at` | date-time | yes |  |

### SectionRequest

| Field | Type | Always there | |
|---|---|---|---|
| `type` | string | yes |  |

### PageMetaRequest

| Field | Type | Always there | |
|---|---|---|---|
| `title` | string |  | The SEO title. Empty removes it. |
| `description` | string |  | The SEO description. Empty removes it. |

### SectionFieldRequestRequest

| Field | Type | Always there | |
|---|---|---|---|
| `key` | string | yes | The property a section carries this field's value under: letters, digits and underscores, starting with a letter. Permanent. |
| `kind` | [SectionFieldKindEnum](#sectionfieldkindenum) |  | `text` when left out. * `text` - text * `long` - long * `list` - list * `link` - link * `flag` - flag * `items` - items * `image` - image |
| `label` | string | yes | What the editor calls it. |
| `help_text` | string |  |  |
| `required` | boolean |  | Whether a published page may leave it empty. |
| `item_label` | string |  | For `items` only: what one entry is called. |
| `item_fields` | list of [RowFieldRequestRequest](#rowfieldrequestrequest) |  | For `items` only, and required by it: the fields of each entry, one level deep. |

### SectionFieldKindEnum

| Field | Type | Always there | |
|---|---|---|---|

### RowFieldRequestRequest

| Field | Type | Always there | |
|---|---|---|---|
| `key` | string | yes |  |
| `kind` | string |  | Any kind but `items`. `text` when left out. |
| `label` | string |  | The key when left out. |
| `help_text` | string |  |  |
| `required` | boolean |  |  |

### DraftSummary

| Field | Type | Always there | |
|---|---|---|---|
| `id` | uuid | yes |  |
| `slug` | string | yes |  |
| `locale` | string | yes |  |
| `title` | string | yes | The draft's title, which the website shows once it is published. |
| `status` | [StatusEnum](#statusenum) | yes |  |
| `live_version` | integer or null | yes | The number of the version the website shows. Null while nothing is published. |
| `changed` | boolean | yes | Whether the draft holds edits the website does not show yet. False while nothing is published. |
| `updated_at` | date-time | yes |  |

### StatusEnum

| Field | Type | Always there | |
|---|---|---|---|

### Section

| Field | Type | Always there | |
|---|---|---|---|
| `type` | string | yes |  |

### PageVersion

| Field | Type | Always there | |
|---|---|---|---|
| `number` | integer | yes |  |
| `title` | string | yes |  |
| `published_at` | date-time | yes |  |
| `restored_from` | integer or null | yes | The version this one copied, when it was published by restoring it. |
| `live` | boolean | yes | Whether this is the version the website shows. |

### PageSummary

| Field | Type | Always there | |
|---|---|---|---|
| `slug` | string | yes |  |
| `locale` | string | yes |  |
| `title` | string | yes |  |
| `updated_at` | date-time | yes |  |
| `version` | integer or null | yes | The live version's number. Null for a test key's draft never published. |

### SectionField

| Field | Type | Always there | |
|---|---|---|---|
| `id` | uuid | yes |  |
| `key` | string | yes | The property a section carries this field's value under. |
| `kind` | [SectionFieldKindEnum](#sectionfieldkindenum) | yes |  |
| `label` | string | yes |  |
| `help_text` | string | yes |  |
| `required` | boolean | yes | Whether a published page may leave it empty. |
| `item_label` | string | yes | What one entry of a repeatable group is called. Empty for any other kind. |
| `item_fields` | list of [RowField](#rowfield) | yes | The fields of each entry of a repeatable group, one level deep. Empty for any other kind. |

### RowField

| Field | Type | Always there | |
|---|---|---|---|
| `key` | string | yes |  |
| `kind` | [RowFieldKindEnum](#rowfieldkindenum) | yes |  |
| `label` | string | yes |  |
| `help_text` | string | yes |  |
| `required` | boolean | yes |  |

### RowFieldKindEnum

| Field | Type | Always there | |
|---|---|---|---|
