> ## 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.

# Changelog

<div id="unified-changelog-layout" aria-hidden="true" />

<Update label="September 30, 2026" tags={["REST API","Latest version"]} rss={{ title: "Workspace-wide message history" }}>
  ### Added

  **Read messages across your workspace.** [`GET /messages`](/docs/2026-03-30/messages/list-messages) now returns a paginated message history across all conversations, newest first. Unlike v1, you don't need to specify a Quo phone number or conversation participants before retrieving messages.

  * **Find the messages that matter.** Filter by sender, exact recipient set, delivery status, direction, Quo phone number, sending user, and creation time. This makes it easier to build workspace-wide reporting or retrieve undelivered and failed messages.
  * **Retrieve a single message.** [`GET /messages/{messageId}`](/docs/2026-03-30/messages/get-a-message-by-id) returns the message's text, conversation ID, delivery status, and attached media. Both read endpoints include media URLs and MIME types when present.

  Message sending remains available through the [v1 API](/docs/mdx/api-reference/messages/send-a-text-message).
</Update>

<Update label="September 30, 2026" tags={["REST API","Latest version"]} rss={{ title: "Phone number discovery and user assignments" }}>
  ### Added

  **Discover the numbers your integration can use.** [`GET /phone-numbers`](/docs/2026-03-30/phone-numbers/list-phone-numbers) and [`GET /phone-numbers/{phoneNumberId}`](/docs/2026-03-30/phone-numbers/get-a-phone-number-by-id) are now available in the `2026-03-30` API. The list endpoint supports cursor pagination and filtering by an E.164 phone number.

  * **Find a user's assigned numbers.** [`GET /users/{userId}/phone-numbers`](/docs/2026-03-30/user-phone-numbers/list-a-users-phone-numbers) provides a dedicated, paginated list of the numbers assigned to a workspace user.
  * **Search available numbers.** [`GET /phone-numbers/available`](/docs/2026-03-30/phone-numbers/get-available-phone-numbers) lets you find numbers by country, area code, city, region, a matching substring, or toll-free availability. This search is new to the API; it does not purchase or provision a number.

  **Moving from v1.** Phone number responses use `phoneNumber` instead of `number`. Calling and messaging restrictions are included with `include=restrictions`, and assigned members are retrieved through [`GET /phone-numbers/{phoneNumberId}/users`](/docs/2026-03-30/phone-numbers/list-the-members-assigned-to-a-phone-number) rather than embedded in each number.
</Update>

<Update label="September 29, 2026" tags={["REST API","Latest version"]} rss={{ title: "Call history, recordings, transcripts, and conversation discovery" }}>
  ### Added

  **Call history with summaries and voicemails in one request.** [`GET /calls`](/docs/2026-03-30/calls/list-calls) and [`GET /calls/{callId}`](/docs/2026-03-30/calls/get-a-call-by-id) are now available in the `2026-03-30` API. Add `include=summary,voicemail` to either endpoint to retrieve that context alongside the call, without separate requests for its summary or voicemail.

  * **Find the calls you need.** List calls across the workspace or filter by Quo phone number, user or AI agent (`actorId`), participant, direction, status, and creation time. Results are paginated, newest first.
  * **Understand who handled each call.** Responses include group-call participants and their actor IDs, who answered or initiated the call, whether AI handled it, and routing and forwarding details.
  * **Retrieve recordings and transcripts.** [`GET /calls/{callId}/recordings`](/docs/2026-03-30/calls/list-recordings-for-a-call) and [`GET /calls/{callId}/transcripts`](/docs/2026-03-30/calls/list-transcripts-for-a-call) return paginated segments in the order they occurred, including multiple segments when recording was paused and resumed.

  **Discover and sync conversations.** [`GET /conversations`](/docs/2026-03-30/conversations/list-conversations) returns a paginated list of workspace conversations. Filter by one or more Quo phone number IDs and by creation or update time, and sort by `createdAt` or `updatedAt` in either direction. Use `updatedAt[gte]` to retrieve conversations changed since your last sync. Responses include participants, the latest activity ID and timestamp, and mute and snooze timestamps.
</Update>

<Update label="September 28, 2026" tags={["REST API","Latest version"]} rss={{ title: "Contact management: records, shares, notes, and properties" }}>
  ### Added

  **More ways to manage contacts.** The `2026-03-30` API now supports creating, updating, and deleting contacts. You can also read a contact's shares and manage notes and properties attached to a contact. The existing list and get-by-ID endpoints remain available.

  | Area | New endpoints |
  | - | - |
  | Contacts | [`POST /contacts`](/docs/2026-03-30/contacts/create-a-contact), [`PATCH /contacts/{contactId}`](/docs/2026-03-30/contacts/update-a-contact-by-id), [`DELETE /contacts/{contactId}`](/docs/2026-03-30/contacts/delete-a-contact) |
  | Shares | [`GET /contacts/{contactId}/shares`](/docs/2026-03-30/contact-shares/list-contact-shares) |
  | Notes | [`GET /contacts/{contactId}/notes`](/docs/2026-03-30/contact-notes/list-notes-for-a-contact), [`POST /contacts/{contactId}/notes`](/docs/2026-03-30/contact-notes/create-a-contact-note), [`GET /contacts/{contactId}/notes/{noteId}`](/docs/2026-03-30/contact-notes/get-a-contact-note-by-id), [`PATCH /contacts/{contactId}/notes/{noteId}`](/docs/2026-03-30/contact-notes/update-a-contact-note), [`DELETE /contacts/{contactId}/notes/{noteId}`](/docs/2026-03-30/contact-notes/delete-a-contact-note) |
  | Properties | [`GET /contacts/{contactId}/properties`](/docs/2026-03-30/contact-properties/list-contact-properties), [`POST /contacts/{contactId}/properties`](/docs/2026-03-30/contact-properties/create-a-contact-property), [`GET /contacts/{contactId}/properties/{propertyId}`](/docs/2026-03-30/contact-properties/get-a-contact-property-by-id), [`PATCH /contacts/{contactId}/properties/{propertyId}`](/docs/2026-03-30/contact-properties/update-a-contact-property), [`DELETE /contacts/{contactId}/properties/{propertyId}`](/docs/2026-03-30/contact-properties/delete-a-contact-property) |
</Update>

<Update label="September 28, 2026" tags={["REST API","Latest version"]} rss={{ title: "Sorting and filtering query conventions" }}>
  ### Added

  **Consistent collection queries.** Collection endpoints now share these conventions where sorting and filtering are supported:

  * **Sort:** Use `sort=field:asc` or `sort=field:desc`. Add more fields, separated by commas, to break ties.
  * **Filter:** Use `field=value` for an exact match or `field[operator]=value` for another comparison. Filters on different fields combine with AND; `[in]` matches any value in a comma-separated set.
  * **Contacts:** [`GET /contacts`](/docs/2026-03-30/contacts/list-contacts) now accepts `externalId` and `source`, including `externalId[in]` and `source[in]` for multiple values.

  See [Sorting and filtering](/docs/2026-03-30/sorting-and-filtering) for syntax and operators, and each endpoint's reference for its supported fields.
</Update>

<Update label="September 22, 2026" tags={["MCP"]} rss={{ title: "Quo MCP: submit product feedback" }}>
  ### Added

  **Send feedback to the Quo product team.** The new `submit-feedback` tool passes along feedback about your phone-line or communications experience. It is opt-in: the client sends feedback only after you explicitly ask it to or accept its offer, and a submission cannot be edited or withdrawn. See [Supported tools](/docs/2026-03-30/mcp/tools#feedback) for details.
</Update>

<Update label="September 18, 2026" tags={["MCP"]} rss={{ title: "Quo MCP: filter fetches by conversation status" }}>
  ### Added

  **Skip done conversations.** `fetch-messages` and `fetch-call-transcripts` now accept `excludeDoneConversations`. Set it to `true` on a whole-inbox query to leave out conversations that are currently marked done or snoozed. It defaults to `false`, so existing calls are unchanged, and queries for one contact always return that contact's full history. See [Supported tools](/docs/2026-03-30/mcp/tools#whole-inbox) for details.
</Update>

<Update label="September 17, 2026" tags={["MCP"]} rss={{ title: "Quo MCP: contact custom fields" }}>
  ### Improved

  **Custom fields on contacts.** `create-contact` and `update-contact` now support your workspace's custom fields. Set custom field values when you create a contact, and set or clear them on an existing contact. See [Supported tools](/docs/2026-03-30/mcp/tools#contacts) for details.
</Update>

<Update label="September 3, 2026" tags={["REST API","Latest version"]} rss={{ title: "Organization: added an endpoint to get organization details" }}>
  ### Added

  **Get the organization.** [`GET /organization`](/docs/2026-03-30/organization/get-the-organization) retrieves information about your Quo workspace, including its name, subscription status, and creation/update timestamps.
</Update>

<Update label="September 2, 2026" tags={["Webhooks","Latest version"]} rss={{ title: "Webhook deliveries: event and resource correlation" }}>
  ### Improved

  **Webhook delivery correlation.** Delivery list and detail results now include the payload `id` as `eventId` and the primary resource ID as `resourceId`. Filter the delivery list by `resourceId` to find every delivery for one business resource. Deliveries created before September 2, 2026 return `null` for both fields, and the `resourceId` filter does not match them. Test deliveries also return `null`. The delivery `id` matches the `webhook-id` header and identifies detail and retry requests.
</Update>

<Update label="August 27, 2026" tags={["REST API","Latest version"]} rss={{ title: "Task endpoints: added task endpoints to get v1 parity" }}>
  ### Added

  **New endpoints supported for tasks in `2026-03-30`**:

  * [`GET /tasks`](/docs/2026-03-30/tasks/list-tasks) — List tasks
  * [`GET /tasks/{taskId}`](/docs/2026-03-30/tasks/get-a-task-by-task-id) — Get a task by ID
  * [`POST /tasks`](/docs/2026-03-30/tasks/create-task) — Create a task
  * [`PATCH /tasks/{taskId}`](/docs/2026-03-30/tasks/update-task) — Update a task's title and/or description
  * [`DELETE /tasks/{taskId}`](/docs/2026-03-30/tasks/delete-task) — Delete a task
  * [`PATCH /tasks/{taskId}/status`](/docs/2026-03-30/tasks/update-the-status-for-a-task) — Update a task's status
  * [`POST /tasks/{taskId}/conversations`](/docs/2026-03-30/tasks/link-a-task-to-a-conversation) — Link a task to a conversation
  * [`DELETE /tasks/{taskId}/conversations`](/docs/2026-03-30/tasks/unlink-a-task-from-a-conversation) — Unlink a task from a conversation
  * [`POST /tasks/{taskId}/users`](/docs/2026-03-30/tasks/assign-a-task-to-a-user) — Assign a task to a user
  * [`DELETE /tasks/{taskId}/users`](/docs/2026-03-30/tasks/unassign-a-task-to-a-user) — Unassign a task from a user
  * [`PATCH /tasks/{taskId}/due-date`](/docs/2026-03-30/tasks/update-the-due-date-of-a-task) — Set a task's due date
  * [`DELETE /tasks/{taskId}/due-date`](/docs/2026-03-30/tasks/delete-the-due-date-of-a-task) — Remove a task's due date
</Update>

<Update label="August 25, 2026" tags={["Webhooks","Latest version"]} rss={{ title: "Webhook endpoints: added message.undelivered event support" }}>
  ### Added

  **Undelivered message event for webhooks.** Create and update webhook endpoints now support the `message.undelivered` event. It fires when an outbound message could not be delivered to the recipient or was blocked. An `undelivered` message is terminal and cannot be retried, unlike a `message.failed` event. See [Webhook event payloads](/docs/2026-03-30/webhooks-event-payloads#message-undelivered) for the schema.
</Update>

<Update label="August 24, 2026" tags={["MCP"]} rss={{ title: "Quo MCP: message attachments and more flexible bulk sends" }}>
  ### Improved

  **Message attachments in fetch results.** `fetch-messages` now returns MMS attachments alongside message text, including each attachment's media type and URL. Connected agents can present images and files as clickable links, including messages that contain an attachment without accompanying text.

  **Larger bulk sends.** `send-bulk-messages` now supports 2–40 recipients per call, up from 20. Every recipient still receives a separate one-to-one message and cannot see the other recipients.

  **Personalized bulk sends.** `send-bulk-messages` can now send different content to each recipient using `messages: [{to, content}]`. For an identical message to everyone, continue using `to` with `content`; provide one mode or the other, not both. See [Supported tools](/docs/2026-03-30/mcp/tools#bulk-message-modes) for details.
</Update>

<Update label="August 21, 2026" tags={["REST API","v1"]} rss={{ title: "Messages endpoints: media array in responses" }}>
  ### Added

  **`media` in message responses.** [`GET /v1/messages`](/docs/mdx/api-reference/messages/list-messages) and [`GET /v1/messages/{id}`](/docs/mdx/api-reference/messages/get-a-message-by-id) now include a `media` array on each message. Each item has a `url` for the attached media and a `type` for its MIME type.
</Update>

<Update label="July 15, 2026" tags={["Webhooks","Latest version"]} rss={{ title: "Webhook endpoints: added phone menu event support" }}>
  ### Added

  **Phone menu event for webhooks.** Create and update webhook endpoints now support the `call.menu.selected` event, which fires when a caller reaches a routing decision in a phone menu (IVR). See [Webhook event payloads](/docs/2026-03-30/webhooks-event-payloads#call-menu-selected) for the schema.
</Update>

<Update label="July 13, 2026" tags={["REST API","Latest version"]} rss={{ title: "Contacts" }}>
  ### Added

  **Get a contact by ID.** [`GET /contacts/{contactId}`](/docs/2026-03-30/contacts/get-a-contact-by-id) retrieves detailed information about a specific contact in your Quo workspace using the contact's unique identifier.
</Update>

<Update label="July 9, 2026" tags={["Webhooks","Latest version"]} rss={{ title: "Webhook endpoints: added task event support" }}>
  ### Added

  **Task events for webhooks.** Create and update webhook endpoints now support `events`: `task.created`, `task.updated`, `task.deleted`, `task.completed`, `task.reopened`, `task.assigned`, `task.unassigned`, `task.overdue`, `task.linked`, `task.unlinked`, `task.duedate.updated`, `task.duedate.removed`.
</Update>

<Update label="July 8, 2026" tags={["REST API","Latest version"]} rss={{ title: "Contacts" }}>
  ### Added

  **List contacts.** [`GET /contacts`](/docs/2026-03-30/contacts/list-contacts) returns a paginated list of contacts. Filter by external ID or source to narrow results.
</Update>

<Update label="June 18, 2026" tags={["Webhooks","Latest version"]} rss={{ title: "Webhooks" }}>
  ### Added

  **Webhook API.** The webhook API is now available in this version. Subscribe an HTTPS endpoint to real-time message, call, and contact events, with signed and automatically retried deliveries. See the [overview](/docs/2026-03-30/webhooks-overview) and [quickstart](/docs/2026-03-30/webhooks-quickstart) to get started.

  **Managing subscriptions.** [`POST /webhooks`](/docs/2026-03-30/webhooks/create-a-new-webhook) creates a subscription; companion endpoints list, update, and delete subscriptions, rotate the signing secret, inspect deliveries, retry a delivery, and send a test event. A workspace can have up to 50 webhooks.

  **Events.** Message (`received`, `delivered`, `failed`), the full call lifecycle, and contact (`updated`, `deleted`) events are supported. See [Webhook event payloads](/docs/2026-03-30/webhooks-event-payloads) for every schema.
</Update>

<Update label="June 18, 2026" tags={["REST API","v1"]} rss={{ title: "Messages endpoints: conversationId in responses and participants filter" }}>
  ### Added

  **`conversationId` in message responses.** All messages endpoints now include `conversationId` in the response body.

  **Group messaging support.** [`GET /v1/messages`](/docs/mdx/api-reference/messages/list-messages) now supports retrieving group conversation messages via the `participants` array.
</Update>

<Update label="June 16, 2026" tags={["REST API","Latest version"]} rss={{ title: "Mark conversations as done or open" }}>
  ### Added

  **Mark a conversation as done.** [`POST /conversations/{conversationId}/mark-as-done`](/docs/2026-03-30/conversations/mark-conversation-as-done) removes a conversation from the inbox without sending a message and returns the updated conversation.

  **Mark a conversation as open.** [`POST /conversations/{conversationId}/mark-as-open`](/docs/2026-03-30/conversations/mark-conversation-as-open) moves a conversation back to the inbox without sending a message and returns the updated conversation.
</Update>

<Update label="June 16, 2026" tags={["REST API","v1"]} rss={{ title: "Mark conversations as done or open" }}>
  ### Added

  **Mark a conversation as done.** [`POST /v1/conversations/{conversationId}/mark-as-done`](/docs/mdx/api-reference/conversations/mark-conversation-as-done) removes a conversation from the inbox without sending a message and returns the updated conversation.

  **Mark a conversation as open.** [`POST /v1/conversations/{conversationId}/mark-as-open`](/docs/mdx/api-reference/conversations/mark-conversation-as-open) moves a conversation back to the inbox without sending a message and returns the updated conversation.
</Update>

<Update label="June 16, 2026" tags={["REST API","v1"]} rss={{ title: "Group messages" }}>
  ### Added

  **Group messages.** [`POST /v1/messages`](/docs/mdx/api-reference/messages/send-a-text-message) now accepts up to 10 phone numbers in the `to` array, sending a single group message to all recipients at once. Sending to a single recipient is unchanged.
</Update>

<Update label="June 15, 2026" tags={["REST API","Latest version"]} rss={{ title: "Mark as read & message retry" }}>
  ### Added

  **Mark a conversation as read.** [`POST /conversations/{conversationId}/mark-as-read`](/docs/2026-03-30/conversations/mark-conversation-as-read) clears a conversation's unread indicator without sending a message and returns the updated conversation.

  **Retry a failed message.** [`POST /messages/{messageId}/retry`](/docs/2026-03-30/messages/retry-a-failed-message) re-attempts delivery of a message in a failed state. Messages that have permanently failed with an error code, and messages in an undelivered state, cannot be retried.
</Update>

<Update label="June 15, 2026" tags={["REST API","v1"]} rss={{ title: "Mark a conversation as read" }}>
  ### Added

  **Mark a conversation as read.** [`POST /v1/conversations/{conversationId}/mark-as-read`](/docs/mdx/api-reference/conversations/mark-conversation-as-read) clears a conversation's unread indicator without sending a message and returns the updated conversation.
</Update>

<Update label="June 8, 2026" tags={["REST API","v1"]} rss={{ title: "Tasks endpoints" }}>
  ### Added

  **Tasks API.** A new set of endpoints for managing tasks is now available.

  | Method | Endpoint | Description |
  | - | - | - |
  | `GET` | [`/v1/tasks`](/docs/mdx/api-reference/tasks/list-tasks) | List tasks with cursor-based pagination. |
  | `POST` | [`/v1/tasks`](/docs/mdx/api-reference/tasks/create-a-task) | Create a task linked to a phone number, conversation, or activity. |
  | `GET` | [`/v1/tasks/{taskId}`](/docs/mdx/api-reference/tasks/gets-a-task-by-id) | Get a task by ID. |
  | `PUT` | [`/v1/tasks/{taskId}`](/docs/mdx/api-reference/tasks/update-a-task) | Update a task's title and description. |
  | `DELETE` | [`/v1/tasks/{taskId}`](/docs/mdx/api-reference/tasks/delete-a-task-by-id) | Delete a task by ID. |
  | `POST` | [`/v1/tasks/{taskId}/complete`](/docs/mdx/api-reference/tasks/complete-a-task) | Mark a task as completed. |
  | `POST` | [`/v1/tasks/{taskId}/reopen`](/docs/mdx/api-reference/tasks/reopen-a-task) | Reopen a completed task. |
  | `POST` | [`/v1/tasks/{taskId}/assign`](/docs/mdx/api-reference/tasks/assign-a-user-to-a-task) | Assign a user to a task. |
  | `POST` | [`/v1/tasks/{taskId}/unassign`](/docs/mdx/api-reference/tasks/unassign-a-user-from-a-task) | Remove a user from a task's assignees. |
  | `POST` | [`/v1/tasks/{taskId}/change-due-date`](/docs/mdx/api-reference/tasks/change-a-tasks-due-date) | Set a task's due date. |
  | `POST` | [`/v1/tasks/{taskId}/remove-due-date`](/docs/mdx/api-reference/tasks/remove-a-tasks-due-date) | Clear a task's due date. |
  | `POST` | [`/v1/tasks/{taskId}/link-conversation`](/docs/mdx/api-reference/tasks/link-a-task-to-a-conversation) | Link a task to a conversation. |
  | `POST` | [`/v1/tasks/{taskId}/unlink-conversation`](/docs/mdx/api-reference/tasks/unlink-a-task-from-a-conversation) | Unlink a conversation from a task. |
</Update>

<Update label="June 5, 2026" tags={["REST API","Latest version"]} rss={{ title: "Users" }}>
  ### Added

  **List users.** `GET /users` returns a paginated list of users in your Quo workspace.

  **Get user by ID.** `GET /users/{userId}` retrieves detailed information about a specific workspace user.
</Update>

<Update label="May 26, 2026" tags={["Webhooks","v1"]} rss={{ title: "Webhooks beta: call events" }}>
  ### Added

  **Call lifecycle events.** Five call lifecycle events are now supported by the beta webhook API, completing event parity with the legacy webhook system:

  | Event type | When it fires |
  | - | - |
  | [`call.ringing`](/docs/mdx/beta/webhooks-event-payloads#call-ringing) | A call started ringing (incoming or outgoing). |
  | [`call.answered`](/docs/mdx/beta/webhooks-event-payloads#call-answered) | A call connected. Also fires when an outgoing call reaches voicemail. |
  | [`call.forwarded`](/docs/mdx/beta/webhooks-event-payloads#call-forwarded) | An incoming call was forwarded. Includes `forwardedFrom` and `forwardedTo` phone numbers. |
  | [`call.missed`](/docs/mdx/beta/webhooks-event-payloads#call-missed) | An incoming call ended without being answered. |
  | [`call.voicemail.completed`](/docs/mdx/beta/webhooks-event-payloads#call-voicemail-completed) | A voicemail finished processing. Correlate with the source call via `resource.callId`. |

  `call.answered`, `call.forwarded`, `call.missed`, and `call.voicemail.completed` are new event types with no equivalent in the legacy webhook system.

  The beta webhook API now covers the full event surface of the legacy system, plus `call.answered`, `call.forwarded`, `call.missed`, and `call.voicemail.completed` — four event types with no equivalent in legacy. See the [beta webhook overview](/docs/mdx/beta/webhooks-overview) and [event payload reference](/docs/mdx/beta/webhooks-event-payloads) for details.
</Update>

<Update label="May 11, 2026" tags={["Webhooks","v1"]} rss={{ title: "Webhooks open beta" }}>
  ### Added

  **Beta webhook API (open beta).** A new webhook API is available in open beta. See the [overview](/docs/mdx/beta/webhooks-overview) and [quickstart](/docs/mdx/beta/webhooks-quickstart) to get started.

  **Unified create endpoint.** `POST /webhooks` replaces the four legacy create endpoints (`/v1/webhooks/messages`, `/v1/webhooks/calls`, `/v1/webhooks/call-summaries`, `/v1/webhooks/call-transcripts`). Message, call, and contact event types can be combined in a single subscription. Up to 50 webhooks per workspace.

  **Supported event types at launch.**

  | Event type | When it fires |
  | - | - |
  | [`message.received`](/docs/mdx/beta/webhooks-event-payloads#message-received) | An inbound message was received. |
  | [`message.delivered`](/docs/mdx/beta/webhooks-event-payloads#message-delivered) | An outbound message was delivered. |
  | [`call.completed`](/docs/mdx/beta/webhooks-event-payloads#call-completed) | A call ended. Includes final status and duration. |
  | [`call.recording.completed`](/docs/mdx/beta/webhooks-event-payloads#call-recording-completed) | A call recording finished processing. |
  | [`call.summary.completed`](/docs/mdx/beta/webhooks-event-payloads#call-summary-completed) | An AI call summary finished generating. |
  | [`call.transcript.completed`](/docs/mdx/beta/webhooks-event-payloads#call-transcript-completed) | A call transcript finished processing. |
  | [`contact.updated`](/docs/mdx/beta/webhooks-event-payloads#contact-updated) | A contact was created or updated. |
  | [`contact.deleted`](/docs/mdx/beta/webhooks-event-payloads#contact-deleted) | A contact was deleted. |

  Call lifecycle events (`call.ringing`, `call.answered`, `call.forwarded`, `call.missed`, `call.voicemail.completed`) were not yet available at launch — they were added on May 26, 2026.

  **Payload envelope.** All events share a common `data.resource` / `data.context` / `data.links` structure. `data.resource` contains the primary business object; `data.context` contains routing metadata (phone number, conversation, participants, contact lookup). See [Webhook event payloads](/docs/mdx/beta/webhooks-event-payloads).

  **Payload versioning.** Each subscription pins a payload version at creation via the `x-quo-api-version` header. Existing subscriptions are unaffected by future version changes. See [Versioning policy](/docs/mdx/beta/webhooks-overview#versioning-policy) for the current version.

  **Signing.** Deliveries use Standard-Webhooks-compatible headers (`webhook-id`, `webhook-timestamp`, `webhook-signature`) and a `whsec_...` base64 secret, compatible with the Svix SDK. This scheme is not interchangeable with the legacy `OpenPhone-Signature` header — update signature verification before routing beta traffic to an existing endpoint. See [Validate webhook signatures](/docs/mdx/beta/webhooks-signature-validation).

  **Delivery inspection.** Send a signed test delivery (`POST /webhooks/:id/events/test`), browse delivery history and per-attempt responses (`GET /webhooks/:id/events`, `GET /webhooks/:id/events/:eventId`), and trigger manual retries (`POST /webhooks/:id/events/:eventId/retry`). See [Webhook API reference](/docs/mdx/beta/webhooks-api-reference).

  **Signing secret rotation.** `POST /webhooks/:id/rotate` issues a new `whsec_...` key for an existing subscription without changing its event subscriptions or `apiVersion`.

  For a side-by-side comparison with the legacy system and a no-downtime migration walkthrough, see [Migrating from legacy](/docs/mdx/beta/webhooks-differences-from-current).
</Update>

<Update label="March 30, 2026" tags={["REST API","Latest version"]} rss={{ title: "2026-03-30 — Initial release" }}>
  ### API versioning

  The Quo API now uses header-based versioning. Specify your target version by passing the `Quo-Api-Version` header on every request:

  ```
  Quo-Api-Version: 2026-03-30
  ```

  **Version policy.** A new version is only introduced when a breaking change is necessary — for example, removing a field, changing a field's type, or altering existing behavior in an incompatible way. New endpoints, new optional fields, and bug fixes are added to the current version without a new version being published. See [Versioning](/docs/2026-03-30/versioning) for the full contract.
</Update>

<Update label="January 22, 2025" tags={["REST API","Bug fixes","v1"]} rss={{ title: "1.2.0" }}>
  ### Minor Changes

  * Adds a property `externalId` to the contact model. Adds `externalId` and `source` as optional parameters to the Create Contact (`POST /contacts`) request.
  * Adds `externalId` and `source` as optional parameters to the Update Contact (`PATCH /contacts/:id`) request.
  * Added a route to list contacts (`GET /contacts`).

  ### Patch Changes

  * Fixed an issue where creating or updating a contact with an invalid custom field would result in 500 error. Sending an invalid custom field will now result in a 400 "Invalid Custom Field Item" error.
</Update>

<Update label="December 6, 2024" tags={["REST API","Bug fixes","v1"]} rss={{ title: "1.1.2" }}>
  ### Patch Changes

  * Fixed an issue where paginated endpoints would return a string token for the next page at the end of paginated results. Now, they will correctly return the next page token as `null`.
  * Added a callout that the `totalItems` result field for the paginated endpoints is not functioning as expected and is not returning the true total items count.
</Update>

<Update label="November 25, 2024" tags={["REST API","Bug fixes","v1"]} rss={{ title: "1.1.1" }}>
  ### Patch Changes

  * Fixes an issue where phone numbers in various routes were expected to be in E164 format, but the format was not being validated correctly.
</Update>

<Update label="November 7, 2024" tags={["REST API","v1"]} rss={{ title: "1.1.0" }}>
  ## 1.1.0

  ### Minor Changes

  * Adds a property, `restrictions`, to the objects in the response from list phone numbers (`GET /phone-numbers`). The new property contains information about regional restrictions for outbound calling and messaging from a phone number.
</Update>

<Update label="November 4, 2024" tags={["REST API","Bug fixes","v1"]} rss={{ title: "1.0.2" }}>
  ### Patch Changes

  * Fixed an issue with list calls (`GET /calls`) where sending an empty participants param resulted in a 500 response. Sending an empty participants param will now result in a descriptive 400 response.
  * Fixes an issue where attempting to send a message to an international number would result in a 500 response if international messaging is not enabled in the workspace. With this fix, the 500 error response changed to a 403 with a descriptive message
  * Fixes a bug where the GET call recordings endpoint sometimes returned an empty array.
  * Fixes an issue that was preventing some call records from returning successfully from `GET /calls`
  * Fixes an issue where getting a contact by id would result in a 500 instead of a 404 when contact is not found. Now this will respond in a 404 with a descriptive message.
  * Fixes an issue where sending a message that contained only whitespace (`' '`, `'\n'`, etc.) resulted in a 500 error response. Now, this will respond with 400 and a validation error message instead.
</Update>

<Update label="October 22, 2024" tags={["REST API","Bug fixes","v1"]} rss={{ title: "1.0.1" }}>
  ### Patch Changes

  * Fixes an issue with List Calls (`GET /calls`) where the user ID applied by default when the user ID parameter was not sent was being set to the workspace owner instead of the phone number owner.
</Update>

<Update label="October 21, 2024" tags={["REST API","v1"]} rss={{ title: "1.0.0" }}>
  ## 1.0.0

  ### Major Changes

  OpenPhone's Public API v1 release 🚀

  Changes from the beta version include:

  * The `since` query parameter on "list calls" and "list messages" has been deprecated. It used to incorrectly behave as a `createdBefore`. Please use `createdAfter` instead, or `createdBefore` to maintain current functionality.
  * The `phoneNumberId` field for "send text message" has been deprecated. Please use `from` instead.
  * `/v0` endpoints have been deprecated. Please use `/v1` instead.
</Update>
