Documentation Index
Fetch the complete documentation index at: https://www.quo.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
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:
| Method | Path | Purpose |
|---|
GET | /webhooks | List webhooks for the workspace. |
POST | /webhooks | Create a webhook. |
GET | /webhooks/:id | Get a webhook. |
PATCH | /webhooks/:id | Update a webhook. |
DELETE | /webhooks/:id | Delete a webhook. |
POST | /webhooks/:id/rotate | Rotate the signing secret. |
Testing & debugging:
| Method | Path | Purpose |
|---|
POST | /webhooks/:id/events/test | Send a test event to the webhook URL. |
GET | /webhooks/:id/events | List deliveries. |
GET | /webhooks/:id/events/:eventId | Get delivery detail including all attempts. |
POST | /webhooks/:id/events/:eventId/retry | Retry a delivery. |
Supported event types
| Event type | When it fires |
|---|
message.received | An inbound SMS, MMS, or message was received by a Quo number. |
message.delivered | An outbound message was delivered. |
call.summary.completed | A call summary finished generating. |
call.transcript.completed | A call transcript finished processing. |
contact.updated | A contact was created or its fields changed. |
contact.deleted | A contact was deleted. |
For payload shapes, see Webhook event payloads.
List webhooks
curl https://api.openphone.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.openphone.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.openphone.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.summary.completed", "message.received", "contact.updated"],
"resourceIds": ["PNabc123"],
"label": "Production webhook",
"status": "enabled"
}'
| Field | Type | Required? | Description |
|---|
url | string | Yes | Public HTTPS endpoint that receives webhook deliveries. |
events | string[] | Yes | One or more supported event types. Message, call summary, call transcript, and contact events can be mixed. |
resourceIds | string[] | No | Phone number ids for message, call summary, and call transcript filtering, or ["*"] for all. Defaults to ["*"]. Contact events are always workspace-wide. |
label | string | No | Human-readable label. |
status | "enabled" | "disabled" | No | Defaults 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.summary.completed", "message.received", "contact.updated"],
"resourceIds": ["PNabc123"],
"apiVersion": "2026-03-30"
}
}
Update a webhook
curl https://api.openphone.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.
| Field | Type | Description |
|---|
url | string | Replaces the webhook URL. |
events | string[] | Replaces the subscribed event types. |
resourceIds | string[] | null | Replaces the phone number filters for message, call summary, and call transcript events. Send null, [], or ["*"] to clear filtering. |
label | string | null | Replaces the label. Send null to clear it. |
status | "enabled" | "disabled" | Enables or disables delivery. |
Delete a webhook
curl https://api.openphone.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.openphone.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.openphone.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.openphone.com/webhooks/123/events?limit=10" \
-H "Authorization: YOUR_API_KEY" \
-H "x-quo-api-version: 2026-03-30"
| Parameter | Type | Description |
|---|
limit | number | Page size. |
after | string | Cursor from the previous response’s nextCursor. |
status | "success" | "pending" | "sending" | "failed" | Filter by delivery status. |
eventTypes | string[] | Restrict results to specific event types. |
createdBefore | ISO-8601 string | Only include deliveries created before this time. |
createdAfter | ISO-8601 string | Only include deliveries created after this time. |
Delivery statuses:
| Status | Meaning |
|---|
success | At least one delivery attempt returned a 2xx response. |
pending | Delivery is queued and has not attempted yet. |
sending | Delivery is in progress or waiting for a retry attempt. |
failed | All 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.openphone.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.openphone.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