---
title: "Submit answers"
method: PUT
path: "/api/v1/questionnaires/{id}"
tags: ["Questionnaires"]
---

# Submit answers

`PUT /api/v1/questionnaires/{id}`

## Request

- Base URL: `https://api.checkcherry.com`
- URL: `https://api.checkcherry.com/api/v1/questionnaires/{id}`
- Auth: none declared. Required headers: `Api-Key`

Saves answers onto a standard questionnaire.

**Answers merge into what is already stored.** A `uuid` you leave out keeps the answer it already has, so you can send just the field you changed without re-sending the rest of the questionnaire.

Merging is **per field, not per element**. The array under a `uuid` you send replaces that field's answers whole, so sending `{"text": "…"}` for a `double_text_field` still drops that entry's `text2`. Send a field's entries complete. Removing a repeat works the same way — send the shorter array — and `[]` clears a field.

Pass `replace: true` to go back to the old behaviour and have `values` stand for the entire questionnaire, deleting any answer you leave out.

`values` is keyed by the field's `uuid` from `data.fieldGroups`. Each key holds an array, one entry per repeat of that field, and each entry is an object keyed by *element* — not by the uuid and not by the question's name. Which element a question stores its answer under is decided entirely by its `type`:

| Field type | Answer stored under |
| --- | --- |
| `header` | _nothing; it only displays something_ |
| `subheader` | _nothing; it only displays something_ |
| `separator` | _nothing; it only displays something_ |
| `plain_text` | _nothing; it only displays something_ |
| `rich_text` | _nothing; it only displays something_ |
| `static_image` | _nothing; it only displays something_ |
| `text_field` | `text` |
| `double_text_field` | `text`, `text2` |
| `triple_text_field` | `text`, `text2`, `text3` |
| `quadruple_text_field` | `text`, `text2`, `text3`, `text4` |
| `text_box` | `text` |
| `dropdown` | `dropdown` |
| `radio_group` | `radio` |
| `checkbox` | `checkbox` |
| `checkbox_group` | `checkbox` |
| `date_field` | `text` |
| `time_field` | `text` |
| `color_picker_field` | `text` |
| `file_uploader_field` | `file` |
| `image_uploader_field` | `file` |
| `e_sign_field` | `signer`, `timestamp`, `ip` |
| `song` | `songName`, `songArtistName`, `songAlbumName`, `songId`, `songProvider`, `spotifyUrl`, `appleMusicUrl`, `youtubeUrl`, `soundCloudUrl`, `songAlbumUrl`, `songPreviewUrl`, `songDurationSeconds`, `songSuggestionListId`, `publicNotes`, `selectionNotes` |
| `song_list` | `songName`, `songArtistName`, `songAlbumName`, `songId`, `songProvider`, `spotifyUrl`, `appleMusicUrl`, `youtubeUrl`, `soundCloudUrl`, `songAlbumUrl`, `songPreviewUrl`, `songDurationSeconds`, `songSuggestionListId`, `publicNotes`, `selectionNotes` |
| `spotify_playlist` | `spotify` |
| `apple_music_playlist` | `appleMusic` |
| `youtube_music_playlist` | `youtubeMusic` |
| `music_playlist` | `musicPlaylist` |

A question with `timelineEnabled` also carries a time, under an element decided by `timelineSettings.timelineMode`:

| `timelineMode` | Also stores |
| --- | --- |
| `length` | `timelineLength` |
| `start_time` | `timelineStartsAt` |
| `start_and_end_time` | `timelineStartsAt`, `timelineEndsAt` |

Answers are checked against the field they belong to, and the call is rejected with a 422 if they do not fit:

- the value for a field must be an array, and each entry an object
- each element name must be one the field actually stores, so a `dropdown` field   will not accept an answer under `radio`
- each value must match the element's type, so a checkbox group takes an array of   the selected labels and a single checkbox takes a boolean

Use `null` to clear an answer; it is accepted for any element. Answers already stored under an element the field no longer declares can be sent back unchanged, so fetching a questionnaire and returning it is always safe, but you cannot introduce a new one.

External questionnaires reject this call with a 422 too: their answers live on the site that hosts them, not in Check Cherry.

**Required permission:** `assigned_event_read` or `unassigned_event_read`, with a key belonging to a staff user and `allow_staff_edit` set on the questionnaire. Customers can submit answers on their own bookings where `allow_customer_edit` is set and the questionnaire is not yet complete.

## Path parameters

- `id` integer, required

## Headers

- `Api-Key` string, required

## Request body

- object
  - `values` QuestionnaireAnswers, required: Answers, keyed by the field's `uuid` from `data.fieldGroups`. Each key holds an array with one entry per repeat of that question, and each entry is an object keyed by element name. Which element names a question uses is decided by its `type`; see the Questionnaires section for the table. `null` clears an answer and is accepted for any element.
  - `replace` boolean: Treat `values` as the whole questionnaire and delete any answer it omits. Leave this off to merge, which is almost always what you want.

## Response `200`

answers saved

## Other responses

- `422`: questionnaire is hosted on another site

---

[API](https://skmtc.dev/checkcherry/apis/check-cherry-business-api.md) · [All operations](https://skmtc.dev/checkcherry/apis/check-cherry-business-api/llms.txt) · [OpenAPI document](https://skmtc.dev/checkcherry/apis/check-cherry-business-api/revisions/84a9aabdf519?raw)
