Customer Alliance Surveys API

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

Operations 5

GET /surveys List published surveys whose owner node is in the key's subtree #
GET /surveys/{id} Get a single published survey (with its published definition) #
GET /surveys/{id}/responses List responses for a survey (newest first) #
GET /surveys/{id}/responses/{responseId}/answers List the answers for a single response #
POST /survey-responses Push survey responses from another tool into a property #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/customer-alliance:customer-alliance-surveys-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

customer-alliance-surveys-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Customer Alliance Surveys API
  summary: Review management, surveys & feedback for hospitality — as an API.
  version: 4.2.0
  description: 'The Customer Alliance API gives you programmatic access to your reviews, surveys, analytics and AI insights, lets you push guests, reviews and survey responses in from your other systems, and lets you subscribe to events via outbound webhooks. ## Getting started


    1. In the dashboard, go to **Settings → API** and create a key, granting only the scopes you need. 2. Copy the key (`ca_live_…`) — it''s shown once. 3. Send it as a Bearer token on every request:


    ```bash

    curl https://app.customer-alliance.com/api/v4/reviews \

    -H "Authorization: Bearer ca_live_your_key_here"

    ```


    Call `GET /whoami` to confirm the key resolves to the account, node and scopes you expect. ## Authentication


    Every request needs `Authorization: Bearer `. Keys are created and scoped in **Settings → API**. ## Scopes


    Each key holds a subset of `reviews:read`, `surveys:read`, `analytics:read`, `insights:read`, `nodes:read`, `webhooks:manage`, `guests:write`, `reviews:write`, `surveys:write`. A call missing its scope returns `403`. ## Hierarchy


    A key is bound to one node in your account hierarchy; **read** endpoints cover that node and its subtree, and **write** endpoints (`POST /guests`, `POST /reviews`, `POST /survey-responses`) write to one property within it. The webhook-management endpoints (`/webhooks*`) are the exception — they operate account-wide and ignore the key''s node binding (see **Webhooks**) — and so are the attribute definitions of `GET /property-attributes`, which describe the account rather than a property (see **Property attributes**). ## Display scope


    By default, read endpoints return everything on your account''s subtree. An API key authenticates the account owner reading their own data — the same data the dashboard shows — so nothing is withheld from you. If the response will be shown to the public, pass `?display=public`:


    ```bash

    curl "https://app.customer-alliance.com/api/v4/reviews?display=public" \

    -H "Authorization: Bearer ca_live_your_key_here"

    ```


    Supported on `GET /reviews` and `GET /reviews/{id}` (`reviews:read`), and `GET /insights/mentions` (`insights:read`). It excludes two groups: review portals whose content may not be republished (some license redisplay as a paid product, or have terms that have not been cleared for it), and sources whose authorship was never verified — reviews entered by hand (`manual`) and imported ones (`upload`: CSV uploads, and everything pushed through `POST /reviews` or `POST /survey-responses`). Only the exact value `public` opts in. Any other value is ignored and you get the default, unfiltered behaviour — deliberately, so that a typo cannot silently withhold data. Rather than tracking which platforms may be republished yourself, use `?display=public` and let the API apply the current set. > **Upgrading an existing integration.** `GET /reviews` previously withheld these platforms from every caller. It no longer does. If you use it to power anything the public sees, add `?display=public` before upgrading — without it you will begin receiving reviews from platforms that may not be republished. If you use it for internal analytics, reporting or warehousing, you need to do nothing; you simply get more complete data. ### Survey responses


    Responses to your Customer Alliance surveys are never returned by `GET /reviews`, `GET /reviews/{id}` or `GET /insights/mentions`, with or without `display=public`. This is not a publishing restriction: a survey-bridged review is a representation of a response that `GET /surveys/{id}/responses` already serves, and returning it from both would make a consumer summing across them count the same feedback twice. To work with survey feedback, use the surveys endpoints. Survey responses imported from another tool — pushed through `POST /survey-responses` or uploaded as a CSV — are the reverse: they are returned by the review endpoints as `upload` reviews, and the surveys endpoints do not list them. Either way, each response is served exactly once.'
  termsOfService: https://www.customer-alliance.com/en/terms-and-conditions/
  contact:
    name: Customer Alliance Support
    email: info@customer-alliance.com
    url: https://www.customer-alliance.com/
servers:
- url: https://app.customer-alliance.com/api/v4
  description: Production
security:
- bearerAuth: []
tags:
- name: Surveys
  description: Surveys, responses and answers (PII-free), and pushing responses in from other survey tools.
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'
  /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'
  /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'
  /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'
  /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**.


        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`.'
      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'
components:
  parameters:
    limit:
      name: limit
      in: query
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    cursor:
      name: cursor
      in: query
      schema:
        type: string
      description: Opaque pagination cursor from a prior response's next_cursor.
  responses:
    Unauthorized:
      description: Missing or invalid API key.
      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'
    BadRequest:
      description: Invalid request.
      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'
    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'
  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'
      example:
        source: Navili
        property_id: 3fa85f64-5717-4562-b3fc-2c963f66afa6
        rating_scale: 5
        responses:
        - external_id: nv-9
          rating: 4
          responded_at: '2026-09-01'
          answers:
            Cleanliness: 5
            What could we improve?: Breakfast could start earlier.
    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.'
    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'
    SurveyDetail:
      allOf:
      - $ref: '#/components/schemas/Survey'
      - type: object
        properties:
          published_definition:
            type: object
            description: The published survey definition (pages/questions).
    SurveyAnswer:
      type: object
      properties:
        id:
          type: string
          format: uuid
        question_id:
          type: string
        question_path:
          type: string
        question_type:
          type: string
          example: rating
        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
      example:
        error: Invalid API key
    Survey:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
        node_id:
          type: string
          format: uuid
        status:
          type: string
          example: published
        primary_language:
          type: string
          example: en
        published_at:
          type:
          - string
          - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
    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
    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
          example: completed
        channel:
          type: string
          example: email
        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
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: An API key created in Settings → API (`ca_live_…`).
externalDocs:
  description: Customer Alliance
  url: https://www.customer-alliance.com/