> For the complete documentation index, see [llms.txt](https://docs.customer-alliance.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.customer-alliance.com/surveys.md).

# Surveys

Surveys, responses and answers (PII-free), and pushing responses in from other survey tools.

## List published surveys whose owner node is in the key's subtree

> Requires \`surveys:read\`.

```json
{"openapi":"3.1.0","info":{"title":"Customer Alliance API","version":"4.2.0"},"tags":[{"name":"Surveys","description":"Surveys, responses and answers (PII-free), and pushing responses in from other survey tools."}],"servers":[{"url":"https://app.customer-alliance.com/api/v4","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key created in Settings → API (`ca_live_…`)."}},"parameters":{"cursor":{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor from a prior response's next_cursor."},"limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}},"schemas":{"Survey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"node_id":{"type":"string","format":"uuid"},"status":{"type":"string"},"primary_language":{"type":"string"},"published_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks the required scope, or the account's plan does not include it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/surveys":{"get":{"summary":"List published surveys whose owner node is in the key's subtree","description":"Requires `surveys:read`.","operationId":"listSurveys","tags":["Surveys"],"parameters":[{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"description":"A page of surveys.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Survey"}},"next_cursor":{"type":["string","null"],"description":"Pass as `?cursor=` to fetch the next page; null on the last page."},"has_more":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}}}}
```

## Get a single published survey (with its published definition)

> Requires \`surveys:read\`.

```json
{"openapi":"3.1.0","info":{"title":"Customer Alliance API","version":"4.2.0"},"tags":[{"name":"Surveys","description":"Surveys, responses and answers (PII-free), and pushing responses in from other survey tools."}],"servers":[{"url":"https://app.customer-alliance.com/api/v4","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key created in Settings → API (`ca_live_…`)."}},"schemas":{"SurveyDetail":{"allOf":[{"$ref":"#/components/schemas/Survey"},{"type":"object","properties":{"published_definition":{"type":"object","description":"The published survey definition (pages/questions)."}}}]},"Survey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string"},"node_id":{"type":"string","format":"uuid"},"status":{"type":"string"},"primary_language":{"type":"string"},"published_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks the required scope, or the account's plan does not include it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not found or outside the key's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/surveys/{id}":{"get":{"summary":"Get a single published survey (with its published definition)","description":"Requires `surveys:read`.","operationId":"getSurvey","tags":["Surveys"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurveyDetail"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## List responses for a survey (newest first)

> Requires \`surveys:read\`. Respondent PII is not included.

```json
{"openapi":"3.1.0","info":{"title":"Customer Alliance API","version":"4.2.0"},"tags":[{"name":"Surveys","description":"Surveys, responses and answers (PII-free), and pushing responses in from other survey tools."}],"servers":[{"url":"https://app.customer-alliance.com/api/v4","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key created in Settings → API (`ca_live_…`)."}},"parameters":{"cursor":{"name":"cursor","in":"query","schema":{"type":"string"},"description":"Opaque pagination cursor from a prior response's next_cursor."},"limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}},"schemas":{"SurveyResponse":{"type":"object","description":"A survey response. Respondent PII (email, personalisation context, tokens) is never exposed.","properties":{"id":{"type":"string","format":"uuid"},"survey_id":{"type":"string","format":"uuid"},"node_id":{"type":"string","format":"uuid"},"status":{"type":"string"},"channel":{"type":"string"},"overall_score":{"type":["number","null"]},"started_at":{"type":"string","format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks the required scope, or the account's plan does not include it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not found or outside the key's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/surveys/{id}/responses":{"get":{"summary":"List responses for a survey (newest first)","description":"Requires `surveys:read`. Respondent PII is not included.","operationId":"listSurveyResponses","tags":["Surveys"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"$ref":"#/components/parameters/cursor"},{"$ref":"#/components/parameters/limit"}],"responses":{"200":{"description":"A page of responses.","content":{"application/json":{"schema":{"type":"object","required":["data","next_cursor","has_more"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SurveyResponse"}},"next_cursor":{"type":["string","null"],"description":"Pass as `?cursor=` to fetch the next page; null on the last page."},"has_more":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## List the answers for a single response

> Requires \`surveys:read\`.

```json
{"openapi":"3.1.0","info":{"title":"Customer Alliance API","version":"4.2.0"},"tags":[{"name":"Surveys","description":"Surveys, responses and answers (PII-free), and pushing responses in from other survey tools."}],"servers":[{"url":"https://app.customer-alliance.com/api/v4","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key created in Settings → API (`ca_live_…`)."}},"schemas":{"SurveyAnswer":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"question_id":{"type":"string"},"question_path":{"type":"string"},"question_type":{"type":"string"},"value":{"description":"The answer value; shape depends on question_type."},"numeric_value":{"type":["number","null"]},"comment":{"type":["string","null"]},"answered_at":{"type":"string","format":"date-time"}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks the required scope, or the account's plan does not include it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Not found or outside the key's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/surveys/{id}/responses/{responseId}/answers":{"get":{"summary":"List the answers for a single response","description":"Requires `surveys:read`.","operationId":"listResponseAnswers","tags":["Surveys"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"responseId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/SurveyAnswer"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}}}}
```

## Push survey responses from another tool into a property

> Requires \`surveys:write\`. Writes up to 100 completed responses, with their answers, from a survey tool Customer Alliance does not run, under a named \`source\` — the automated form of the review inbox's survey CSV upload. Each source's responses are kept in one survey managed for you and hidden from the survey endpoints and statistics; each response also appears in the inbox, and in \`GET /reviews\`, as an \`upload\` review. See \*\*Pushing reviews and survey responses\*\*.\
> \
> In \`answers\`, a number answers a rating question and a string a free-text one. A question keeps the type — and, for a rating, the scale — it was first given: answering it otherwise later is a \`422\`, as is growing the source's survey past its question limit, and nothing is written. Identity is (source, \`external\_id\`): a repeat push replaces that response's answers. Each item's outcome is in \`results\`.

```json
{"openapi":"3.1.0","info":{"title":"Customer Alliance API","version":"4.2.0"},"tags":[{"name":"Surveys","description":"Surveys, responses and answers (PII-free), and pushing responses in from other survey tools."}],"servers":[{"url":"https://app.customer-alliance.com/api/v4","description":"Production"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"An API key created in Settings → API (`ca_live_…`)."}},"schemas":{"SurveyResponsePushInput":{"type":"object","required":["source","rating_scale","responses"],"additionalProperties":false,"description":"A batch of completed survey responses for one property, from one source. Validation is all-or-nothing.","properties":{"source":{"type":"string","minLength":1,"maxLength":120,"description":"Where the data comes from, e.g. Zenchef. Created on first use and matched case-insensitively after that — the same sources the review inbox's CSV upload offers."},"property_id":{"type":"string","format":"uuid","description":"The property (leaf node) to write to. Optional when the key is bound to a single property; required when it is bound to a group. Must be within the key's node scope."},"rating_scale":{"type":"integer","enum":[5,10,100],"description":"The scale every rating in the batch is on."},"responses":{"type":"array","minItems":1,"maxItems":100,"items":{"$ref":"#/components/schemas/SurveyResponsePushItem"}}}},"SurveyResponsePushItem":{"type":"object","required":["external_id","rating","responded_at","answers"],"additionalProperties":false,"properties":{"external_id":{"type":"string","minLength":1,"maxLength":255,"description":"Your id for this response: its identity within the source. A repeat push replaces the stored response and its answers."},"rating":{"type":"number","description":"The response's overall score, on the batch's `rating_scale`."},"responded_at":{"anyOf":[{"type":"string","format":"date"},{"type":"string","format":"date-time"}],"description":"When the response was completed. An ISO-8601 date (kept as that calendar day) or a date-time with its zone (`Z` or an offset such as `+02:00`); a date-time without a zone is refused."},"author_name":{"type":["string","null"],"maxLength":200,"description":"Defaults to the name of the guest matched by `email`, when there is one. Not stored when the hotel has anonymized a review from the same `email`: the item is stored anonymized."},"email":{"type":["string","null"],"format":"email","description":"The guest's email. Links the item to a guest with that email at the property and makes it reachable by GDPR erasure and export; an email erased under GDPR is skipped. Never returned by the read endpoints."},"language":{"type":["string","null"],"description":"e.g. en or en-GB."},"answers":{"type":"object","description":"Question label (in any language) → answer. A number answers a rating question (on the batch's `rating_scale`), a string a free-text question, and null leaves it unanswered; at least one question must be answered. A question keeps the type — and, for a rating, the scale — it was first given, and a source's survey holds at most 200 questions. Free-text answers become the inbox review's text.","additionalProperties":{"type":["number","string","null"]},"maxProperties":100}}},"SurveyResponsePushResult":{"type":"object","required":["source","property_id","created","updated","skipped","results"],"properties":{"source":{"$ref":"#/components/schemas/PushSource"},"property_id":{"type":"string","format":"uuid"},"created":{"type":"integer"},"updated":{"type":"integer"},"skipped":{"type":"integer"},"results":{"type":"array","description":"One outcome per item, in request order.","items":{"$ref":"#/components/schemas/SurveyResponsePushOutcome"}}}},"PushSource":{"type":"object","description":"The upload source a push landed under — the same sources the review inbox's CSV upload offers.","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}}},"SurveyResponsePushOutcome":{"type":"object","required":["external_id","status","response_id","review_id"],"properties":{"external_id":{"type":"string"},"status":{"type":"string","enum":["created","updated","skipped"]},"response_id":{"type":["string","null"],"format":"uuid","description":"The stored survey response; null when skipped."},"review_id":{"type":["string","null"],"format":"uuid","description":"The review it appears as in the inbox and in `GET /reviews`; null when skipped."},"reason":{"type":"string","enum":["erased","other_property"],"description":"Present when `status` is `skipped`. `erased`: the email belongs to a guest erased under GDPR. `other_property`: this external_id already belongs to a different property in this source; a push never moves a record between properties."}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string"}}}},"responses":{"BadRequest":{"description":"Invalid request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"The key lacks the required scope, or the account's plan does not include it.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Rate limit exceeded. Honour the `Retry-After` header.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/survey-responses":{"post":{"summary":"Push survey responses from another tool into a property","description":"Requires `surveys:write`. Writes up to 100 completed responses, with their answers, from a survey tool Customer Alliance does not run, under a named `source` — the automated form of the review inbox's survey CSV upload. Each source's responses are kept in one survey managed for you and hidden from the survey endpoints and statistics; each response also appears in the inbox, and in `GET /reviews`, as an `upload` review. See **Pushing reviews and survey responses**.\n\nIn `answers`, a number answers a rating question and a string a free-text one. A question keeps the type — and, for a rating, the scale — it was first given: answering it otherwise later is a `422`, as is growing the source's survey past its question limit, and nothing is written. Identity is (source, `external_id`): a repeat push replaces that response's answers. Each item's outcome is in `results`.","operationId":"pushSurveyResponses","tags":["Surveys"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurveyResponsePushInput"}}}},"responses":{"200":{"description":"The batch was processed; see each item's `status`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SurveyResponsePushResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"description":"property_id is missing, out of scope, or not a property (leaf) node; or the batch contradicts a question's established type or scale, or would take the source's survey past its question limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
```
