Customer Alliance Webhook events API

The signed events Customer Alliance POSTs to your endpoints.

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-webhook-events-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-webhook-events-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Customer Alliance Webhook events 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: Webhook events
  description: The signed events Customer Alliance POSTs to your endpoints.
paths: {}
webhooks:
  review.received:
    post:
      summary: '`review.received` delivered to your endpoint'
      description: Your endpoint receives this POST. Respond 2xx to acknowledge; non-2xx (and 3xx) are retried with backoff.
      operationId: webhook_review_received
      tags:
      - Webhook events
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  event:
                    const: review.received
                  data:
                    $ref: '#/components/schemas/ReviewReceivedData'
      responses:
        '200':
          description: Acknowledged.
  review.replied:
    post:
      summary: '`review.replied` delivered to your endpoint'
      description: Your endpoint receives this POST. Respond 2xx to acknowledge; non-2xx (and 3xx) are retried with backoff.
      operationId: webhook_review_replied
      tags:
      - Webhook events
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  event:
                    const: review.replied
                  data:
                    $ref: '#/components/schemas/ReviewRepliedData'
      responses:
        '200':
          description: Acknowledged.
  review.alert_triggered:
    post:
      summary: '`review.alert_triggered` delivered to your endpoint'
      description: Your endpoint receives this POST. Respond 2xx to acknowledge; non-2xx (and 3xx) are retried with backoff.
      operationId: webhook_review_alert_triggered
      tags:
      - Webhook events
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  event:
                    const: review.alert_triggered
                  data:
                    $ref: '#/components/schemas/ReviewAlertTriggeredData'
      responses:
        '200':
          description: Acknowledged.
  survey.response_completed:
    post:
      summary: '`survey.response_completed` delivered to your endpoint'
      description: Your endpoint receives this POST. Respond 2xx to acknowledge; non-2xx (and 3xx) are retried with backoff.
      operationId: webhook_survey_response_completed
      tags:
      - Webhook events
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  event:
                    const: survey.response_completed
                  data:
                    $ref: '#/components/schemas/SurveyResponseCompletedData'
      responses:
        '200':
          description: Acknowledged.
  guest.created:
    post:
      summary: '`guest.created` delivered to your endpoint'
      description: Your endpoint receives this POST. Respond 2xx to acknowledge; non-2xx (and 3xx) are retried with backoff.
      operationId: webhook_guest_created
      tags:
      - Webhook events
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  event:
                    const: guest.created
                  data:
                    $ref: '#/components/schemas/GuestCreatedData'
      responses:
        '200':
          description: Acknowledged.
  guest.unsubscribed:
    post:
      summary: '`guest.unsubscribed` delivered to your endpoint'
      description: Your endpoint receives this POST. Respond 2xx to acknowledge; non-2xx (and 3xx) are retried with backoff.
      operationId: webhook_guest_unsubscribed
      tags:
      - Webhook events
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
              - $ref: '#/components/schemas/WebhookEnvelope'
              - type: object
                properties:
                  event:
                    const: guest.unsubscribed
                  data:
                    $ref: '#/components/schemas/GuestUnsubscribedData'
      responses:
        '200':
          description: Acknowledged.
components:
  schemas:
    GuestUnsubscribedData:
      type: object
      properties:
        guest_id:
          type:
          - string
          - 'null'
          format: uuid
        unsubscribe_id:
          type: string
          format: uuid
    WebhookEnvelope:
      type: object
      description: 'Every delivery POSTs this envelope. Verify the `X-CA-Signature: sha256=<hex>` header — an HMAC-SHA256 of the raw request body keyed by your endpoint''s signing secret — before trusting it.'
      required:
      - id
      - event
      - created_at
      - data
      properties:
        id:
          type: string
          format: uuid
          description: Delivery id (also in the X-CA-Delivery-Id header); stable across retries — use it to dedupe.
        event:
          type: string
          enum:
          - review.received
          - review.replied
          - review.alert_triggered
          - survey.response_completed
          - guest.created
          - guest.unsubscribed
        created_at:
          type: string
          format: date-time
        data:
          type: object
          description: The event payload; shape depends on `event` (see the schemas below).
    ReviewReceivedData:
      type: object
      description: 'Carries the whole review, so you do not need a follow-up `GET /reviews/{id}` to act on the event. `review` is the same shape that endpoint returns, and `sentiment` may still be null — unrated reviews are classified asynchronously, after this event fires. `review_id`, `node_id` and `platform` are duplicated at the top level for consumers written against the original payload.


        Which reviews fire this event: those ingested from a connected portal, plus `manual` and `upload` (CSV uploads and reviews pushed through `POST /reviews`). Only recent reviews fire it, so a first sync or a backfill of older history does not flood your endpoint. Survey responses do NOT — whether collected by a Customer Alliance survey or pushed through `POST /survey-responses` — because a survey-bridged review is written by a different path that emits no webhook; do not wait on this event for them, and read `GET /surveys/{id}/responses` for your own surveys instead. Every review delivered here is also served by `GET /reviews`.'
      properties:
        review_id:
          type: string
          format: uuid
        node_id:
          type: string
          format: uuid
        platform:
          type: string
        review:
          $ref: '#/components/schemas/Review'
    ReviewAlertTriggeredData:
      type: object
      description: 'Note: this payload uses camelCase keys (historical).'
      properties:
        alertId:
          type: string
          format: uuid
        ruleId:
          type: string
          format: uuid
        type:
          type: string
        message:
          type: string
        context:
          type: object
    SurveyResponseCompletedData:
      type: object
      properties:
        survey_id:
          type: string
          format: uuid
        response_id:
          type: string
          format: uuid
        node_id:
          type: string
          format: uuid
        overall_score:
          type:
          - number
          - 'null'
    GuestCreatedData:
      type: object
      properties:
        guest_id:
          type: string
          format: uuid
        node_id:
          type: string
          format: uuid
        source:
          type: string
          example: import
    Review:
      type: object
      description: A collected review. Hidden reviews are included and flagged `is_hidden`; the owner's own reply text is `owner_reply`.
      properties:
        id:
          type: string
          format: uuid
        platform:
          type: string
          example: google
        external_id:
          type: string
          description: The review's id on the source platform.
        author:
          type:
          - string
          - 'null'
          description: Null when the review is anonymised.
        rating:
          type:
          - number
          - 'null'
          description: Rating on a 0–5 scale.
        rating_normalized:
          type:
          - number
          - 'null'
          description: Rating normalised to 0–100.
        title:
          type:
          - string
          - 'null'
        text:
          type:
          - string
          - 'null'
        url:
          type:
          - string
          - 'null'
          description: Where to manage this review on the source platform — not a guest-facing link. May require a portal login and may embed internal property identifiers. Do not republish it publicly.
        language:
          type:
          - string
          - 'null'
        sentiment:
          type:
          - string
          - 'null'
          description: positive | neutral | negative | null.
        owner_reply:
          type:
          - string
          - 'null'
        replied_at:
          type:
          - string
          - 'null'
          format: date-time
        reviewed_at:
          type: string
          format: date-time
        node_id:
          type: string
          format: uuid
        is_hidden:
          type: boolean
    ReviewRepliedData:
      type: object
      properties:
        review_id:
          type: string
          format: uuid
        node_id:
          type: string
          format: uuid
        reply_id:
          type: string
          format: uuid
  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/