Customer Alliance Webhooks API
Manage outbound webhook endpoints and inspect deliveries. Account-scoped: these endpoints ignore the key's node binding (unlike the read endpoints).
Manage outbound webhook endpoints and inspect deliveries. Account-scoped: these endpoints ignore the key's node binding (unlike the read endpoints).
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
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.curl "https://apis.io/api/v1/apis/customer-alliance:customer-alliance-webhooks-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
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: 3.2.0
info:
title: Customer Alliance Webhooks 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: Webhooks
description: 'Manage outbound webhook endpoints and inspect deliveries. Account-scoped: these endpoints ignore the key''s node binding (unlike the read endpoints).'
paths:
/webhooks:
get:
summary: List the account's outbound webhook endpoints
description: Requires `webhooks:manage`. Signing secrets are never returned.
operationId: listWebhooks
tags:
- Webhooks
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required:
- data
properties:
data:
type: array
items:
$ref: '#/components/schemas/WebhookEndpoint'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
post:
summary: Register an outbound webhook endpoint
description: Requires `webhooks:manage`. The signing secret is returned exactly once — store it now.
operationId: createWebhook
tags:
- Webhooks
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/WebhookEndpointInput'
responses:
'201':
description: Created — secret shown once.
content:
application/json:
schema:
$ref: '#/components/schemas/WebhookEndpointCreated'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'409':
description: Per-account endpoint limit reached.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/webhooks/{id}:
patch:
summary: Update a webhook endpoint
description: Requires `webhooks:manage`. Any subset of name / url / events / is_active.
operationId: updateWebhook
tags:
- Webhooks
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/WebhookEndpointInput'
responses:
'200':
description: OK
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
delete:
summary: Delete a webhook endpoint (cascades its deliveries)
description: Requires `webhooks:manage`.
operationId: deleteWebhook
tags:
- Webhooks
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: OK
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
/webhooks/{id}/deliveries:
get:
summary: Recent delivery attempts for one endpoint (newest first)
description: Requires `webhooks:manage`.
operationId: listWebhookDeliveries
tags:
- Webhooks
parameters:
- name: id
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/WebhookDelivery'
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
/webhooks/{id}/test:
post:
summary: Send a test `ping` delivery to one endpoint
description: Requires `webhooks:manage`. Queues a signed ping regardless of the endpoint's subscribed events.
operationId: testWebhook
tags:
- Webhooks
parameters:
- name: id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: OK — ping queued.
'401':
$ref: '#/components/responses/Unauthorized'
'403':
$ref: '#/components/responses/Forbidden'
'404':
$ref: '#/components/responses/NotFound'
components:
responses:
Unauthorized:
description: Missing or invalid API key.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
BadRequest:
description: Invalid request.
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'
schemas:
WebhookDelivery:
type: object
properties:
id:
type: string
format: uuid
event_type:
type: string
status:
type: string
enum:
- pending
- delivered
- failed
attempt_count:
type: integer
last_status_code:
type:
- integer
- 'null'
last_attempt_at:
type:
- string
- 'null'
format: date-time
created_at:
type: string
format: date-time
WebhookEndpointInput:
type: object
required:
- name
- url
- events
properties:
name:
type: string
minLength: 1
maxLength: 120
url:
type: string
format: uri
description: Delivery URL. Must be http(s); private/reserved addresses are rejected at delivery time.
events:
type: array
minItems: 1
items:
type: string
enum:
- review.received
- review.replied
- review.alert_triggered
- survey.response_completed
- guest.created
- guest.unsubscribed
is_active:
type: boolean
description: PATCH only — pause/resume deliveries without deleting the endpoint.
example:
name: Prod integration
url: https://example.com/hooks/ca
events:
- review.received
- survey.response_completed
Error:
type: object
required:
- error
properties:
error:
type: string
example:
error: Invalid API key
WebhookEndpointCreated:
type: object
required:
- secret
- endpoint
properties:
secret:
type: string
description: The signing secret (`whsec_…`). Returned exactly once — store it now; you cannot retrieve it again.
example: whsec_XXXXXXXXXXXXXXXXXXXXXXXX
endpoint:
$ref: '#/components/schemas/WebhookEndpoint'
WebhookEndpoint:
type: object
description: A registered outbound webhook endpoint. The signing secret is never returned after creation.
properties:
id:
type: string
format: uuid
name:
type: string
url:
type: string
format: uri
events:
type: array
items:
type: string
enum:
- review.received
- review.replied
- review.alert_triggered
- survey.response_completed
- guest.created
- guest.unsubscribed
is_active:
type: boolean
created_at:
type: string
format: date-time
updated_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/