Skip to main content
This is the beta webhook API, available in open beta. For the existing webhook system, see Legacy webhooks.
Use these endpoints to create, manage, test, and inspect webhooks created with the beta API. Endpoints are grouped into CRUD (create/read/update/delete) and Testing & debugging.
Webhooks created through these endpoints are managed through these endpoints and do not appear in the Quo app webhook settings during the beta.
Every request requires your Public API key and the API version header:
Authorization: YOUR_API_KEY
x-quo-api-version: 2026-03-30

Endpoint index

CRUD:
MethodPathPurpose
GET/webhooksList webhooks for the workspace.
POST/webhooksCreate a webhook.
GET/webhooks/:idGet a webhook.
PATCH/webhooks/:idUpdate a webhook.
DELETE/webhooks/:idDelete a webhook.
POST/webhooks/:id/rotateRotate the signing secret.
Testing & debugging:
MethodPathPurpose
POST/webhooks/:id/events/testSend a test event to the webhook URL.
GET/webhooks/:id/eventsList deliveries.
GET/webhooks/:id/events/:eventIdGet delivery detail including all attempts.
POST/webhooks/:id/events/:eventId/retryRetry a delivery.

Supported event types

Event typeWhen it fires
message.receivedAn inbound SMS, MMS, or message was received by a Quo number.
message.deliveredAn outbound message was delivered.
message.failedAn outbound message failed to deliver.
call.ringingA call started ringing. Fires for incoming and outgoing.
call.answeredA call was connected. answeredByUserId identifies the Quo-side user associated with the answer when known. Outgoing calls fire this event for voicemail pickup too.
call.completedA call ended. Terminal lifecycle event with final status and duration.
call.forwardedAn incoming call was forwarded. Includes the forwarding phone numbers.
call.missedAn incoming call ended without being answered.
call.recording.completedA call recording finished processing.
call.summary.completedA call summary finished generating.
call.transcript.completedA call transcript finished processing.
call.voicemail.completedA voicemail was left and finished processing.
contact.updatedA contact was created or its fields changed.
contact.deletedA contact was deleted.
For payload shapes, see Webhook event payloads.

List webhooks

curl https://api.quo.com/webhooks \
  -H "Authorization: YOUR_API_KEY" \
  -H "x-quo-api-version: 2026-03-30"
Returns all webhooks created through the beta webhook endpoints for the workspace. This endpoint is not paginated.
{
  "data": [
    {
      "id": "123",
      "orgId": "OR123",
      "label": "Production webhook",
      "status": "enabled",
      "url": "https://example.com/webhooks/quo",
      "createdAt": "2026-04-13T12:00:00.000Z",
      "updatedAt": "2026-04-13T12:00:00.000Z",
      "events": ["call.summary.completed", "contact.updated"],
      "resourceIds": ["PNabc123"],
      "apiVersion": "2026-03-30"
    }
  ]
}

Get a webhook

curl https://api.quo.com/webhooks/123 \
  -H "Authorization: YOUR_API_KEY" \
  -H "x-quo-api-version: 2026-03-30"
{
  "data": {
    "id": "123",
    "orgId": "OR123",
    "label": "Production webhook",
    "status": "enabled",
    "url": "https://example.com/webhooks/quo",
    "createdAt": "2026-04-13T12:00:00.000Z",
    "updatedAt": "2026-04-13T12:00:00.000Z",
    "events": ["call.summary.completed", "contact.updated"],
    "resourceIds": ["PNabc123"],
    "apiVersion": "2026-03-30"
  }
}

Create a webhook

curl https://api.quo.com/webhooks \
  -X POST \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-quo-api-version: 2026-03-30" \
  -d '{
    "url": "https://example.com/webhooks/quo",
    "events": ["call.completed", "message.received", "contact.updated"],
    "resourceIds": ["PNabc123"],
    "label": "Production webhook",
    "status": "enabled"
  }'
FieldTypeRequired?Description
urlstringYesPublic HTTPS endpoint that receives webhook deliveries.
eventsstring[]YesOne or more supported event types. Message, call, and contact events can be mixed in a single subscription.
resourceIdsstring[]NoPhone number ids for filtering message and call events, or ["*"] for all. Defaults to ["*"]. Contact events are always workspace-wide.
labelstringNoHuman-readable label.
status"enabled" | "disabled"NoDefaults to enabled.
The response includes the whsec_… signing secret. Save it as an environment variable — see Validate webhook signatures.
{
  "data": {
    "id": "123",
    "orgId": "OR123",
    "label": "Production webhook",
    "status": "enabled",
    "url": "https://example.com/webhooks/quo",
    "key": "whsec_...",
    "createdAt": "2026-04-13T12:00:00.000Z",
    "updatedAt": "2026-04-13T12:00:00.000Z",
    "events": ["call.completed", "message.received", "contact.updated"],
    "resourceIds": ["PNabc123"],
    "apiVersion": "2026-03-30"
  }
}

Update a webhook

curl https://api.quo.com/webhooks/123 \
  -X PATCH \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-quo-api-version: 2026-03-30" \
  -d '{
    "events": ["call.summary.completed", "contact.updated"],
    "resourceIds": ["PNabc123"],
    "label": "Updated webhook"
  }'
All fields are optional. Provide only the fields you want to change.
FieldTypeDescription
urlstringReplaces the webhook URL.
eventsstring[]Replaces the subscribed event types.
resourceIdsstring[] | nullReplaces the phone number filters for message and call events. Send null, [], or ["*"] to clear filtering.
labelstring | nullReplaces the label. Send null to clear it.
status"enabled" | "disabled"Enables or disables delivery.

Delete a webhook

curl https://api.quo.com/webhooks/123 \
  -X DELETE \
  -H "Authorization: YOUR_API_KEY" \
  -H "x-quo-api-version: 2026-03-30"
Returns 204 No Content on success.

Rotate the signing secret

curl https://api.quo.com/webhooks/123/rotate \
  -X POST \
  -H "Authorization: YOUR_API_KEY" \
  -H "x-quo-api-version: 2026-03-30"
{
  "data": { "key": "whsec_..." }
}
Store the new key and use it for future signature verification. See Validate webhook signatures.

Send a test event

Sends a real, signed delivery to your webhook URL — the same as a production event — and returns the sample payload inline so you can inspect it without waiting for the delivery to land.
curl https://api.quo.com/webhooks/123/events/test \
  -X POST \
  -H "Authorization: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "x-quo-api-version: 2026-03-30" \
  -d '{ "eventType": "message.received" }'
eventType must be one of the supported event types. The response is the sample payload sent to your webhook URL. Delivery is asynchronous; use GET /webhooks/:id/events to find the delivery id and inspect what your endpoint returned.
{
  "id": "EV-test-message-received",
  "apiVersion": "2026-03-30",
  "createdAt": "2026-03-30T18:00:00.000Z",
  "type": "message.received",
  "data": {
    "resource": {
      "id": "ACsampleactivity0000000000000000",
      "direction": "incoming",
      "text": "Hello from Quo! This is a sample message.",
      "status": "received",
      "createdAt": "2026-03-30T18:00:00.000Z"
    },
    "context": {
      "phoneNumberId": "PNsamplephonenumber000000000000",
      "conversationId": "CNsampleconversation000000000000",
      "userId": "USsampleus",
      "contacts": { "ids": ["CTsampleContact01234"], "lookupStatus": "matched" },
      "senderIdentifier": "+15555551234",
      "recipientIdentifiers": ["+15555555678"]
    },
    "links": { "quo": "https://my.quo.com/..." }
  }
}

List deliveries

curl "https://api.quo.com/webhooks/123/events?limit=10" \
  -H "Authorization: YOUR_API_KEY" \
  -H "x-quo-api-version: 2026-03-30"
ParameterTypeDescription
limitnumberPage size.
afterstringCursor from the previous response’s nextCursor.
status"success" | "pending" | "sending" | "failed"Filter by delivery status.
eventTypesstring[]Restrict results to specific event types.
createdBeforeISO-8601 stringOnly include deliveries created before this time.
createdAfterISO-8601 stringOnly include deliveries created after this time.
Delivery statuses:
StatusMeaning
successAt least one delivery attempt returned a 2xx response.
pendingDelivery is queued and has not attempted yet.
sendingDelivery is in progress or waiting for a retry attempt.
failedAll retry attempts have been exhausted without a 2xx response.
{
  "data": [
    {
      "id": "msg_2abcDEFghiJKLmnoPQRstu",
      "eventType": "message.received",
      "status": "success",
      "nextAttemptAt": null,
      "createdAt": "2026-04-13T12:00:00.000Z"
    }
  ],
  "nextCursor": "eyJsYXN0SWQiOiJtc2dfMmFiY0RFRmdoaUpLTG1ub1BRUnN0dSJ9"
}

Get delivery detail

curl https://api.quo.com/webhooks/123/events/msg_2abcDEFghiJKLmnoPQRstu \
  -H "Authorization: YOUR_API_KEY" \
  -H "x-quo-api-version: 2026-03-30"
Delivery detail includes the request body and all attempts, ordered most-recent first.
{
  "data": {
    "id": "msg_2abcDEFghiJKLmnoPQRstu",
    "eventType": "message.received",
    "createdAt": "2026-04-13T12:00:00.000Z",
    "requestBody": {
      "id": "EV123",
      "apiVersion": "2026-03-30",
      "createdAt": "2026-04-13T12:00:00.000Z",
      "type": "message.received",
      "data": {
        "resource": {
          "id": "AC-message",
          "direction": "incoming",
          "text": "hello",
          "status": "received",
          "createdAt": "2026-04-13T12:00:00.000Z"
        },
        "context": {
          "phoneNumberId": "PN123",
          "conversationId": "CN123",
          "userId": "US123",
          "contacts": { "ids": ["CT123"], "lookupStatus": "matched" },
          "senderIdentifier": "+15550001111",
          "recipientIdentifiers": ["+15550002222"]
        },
        "links": { "quo": "https://my.quo.com/inbox/..." }
      }
    },
    "attempts": [
      {
        "id": "atmpt_2abcDEFghiJKLmnoPQRstu",
        "timestamp": "2026-04-13T12:00:01.000Z",
        "status": "success",
        "responseStatusCode": 200,
        "responseBody": "{\"ok\":true}",
        "responseDurationMs": 123,
        "triggerType": "scheduled",
        "url": "https://example.com/webhooks/quo"
      }
    ]
  }
}

Retry a delivery

curl https://api.quo.com/webhooks/123/events/msg_2abcDEFghiJKLmnoPQRstu/retry \
  -X POST \
  -H "Authorization: YOUR_API_KEY" \
  -H "x-quo-api-version: 2026-03-30"
The retry is queued asynchronously and returns 202 Accepted. Use GET /webhooks/:id/events/:eventId to inspect the new attempt.

See also