> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.telekesher.dev/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.telekesher.dev/_mcp/server.

# API changelog

Use this page to track changes that can affect an application built on the
Voice Platform API. Entries describe the public behavior of the API and any
action an existing integration should take.

## How changes are published

Changes are grouped by release date and labeled as follows:

* **Added** — a new, backward-compatible capability.
* **Changed** — an existing contract or behavior changed. The entry includes
  migration guidance when an application may need to change.
* **Fixed** — the implementation or documentation was corrected to match the
  intended contract.
* **Deprecated** — a capability remains available but should no longer be used.
  The entry identifies its replacement and the planned removal timeline.

The endpoint reference remains the source for the current contract. This page
records the history needed to understand differences between an existing
integration and the current contract.

## August 7, 2026

### Added

* Applications can read and update their own webhook delivery URL with
  [`GET /api/v1/app/webhook`](api:voice-api:GET/api/v1/app/webhook) and
  [`PUT /api/v1/app/webhook`](api:voice-api:PUT/api/v1/app/webhook). Sending
  `null` or an empty string disables delivery; a successful update applies to
  webhook deliveries created afterward.
* Unauthenticated [`GET /health`](api:voice-api:GET/health) and
  [`GET /livez`](api:voice-api:GET/livez) endpoints are now part of the public
  contract. Use `/health` for dependency readiness and `/livez` only for
  process liveness.

### Changed

* The canonical API base URL is `https://api.telekesher.dev`. Session endpoints
  moved from `/api/v1/sessions...` to `/v1/sessions...`. Update constructed
  request URLs to remove the `/api` segment from Session routes.

## August 6, 2026

### Changed

* Session webhook names now use the `session` resource namespace:
  `call.created`, `call.answered`, `call.ringing_started`,
  `call.early_media_started`, and `call.ended` became their corresponding
  `session.*` events, and `command.call.dial.accepted` became
  `command.session.dial.accepted`. Update event filters and webhook dispatch
  logic to use the new names.
* Terminal room playback events are now `room.playback.ended` for natural
  completion or an API stop, and `room.playback.failed` for errors and
  timeouts. The former `room.playback.finished` name is no longer used.
  Inspect the event's `reason` to distinguish the terminal outcome.
* Session lifecycle fields are endpoint-specific. Items returned by
  [`GET /sessions`](api:voice-api:GET/v1/sessions) use `state`, while
  [`GET /sessions/{session_uuid}`](api:voice-api:GET/v1/sessions/\{session_uuid})
  uses `status`. Both fields have the same lifecycle values. Applications that
  deserialize both responses into one model should accept the field associated
  with each endpoint.
* `playback/seek`, `recording/mask`, and `recording/unmask` draw from one shared
  `seek` rate-limit bucket. A burst of one of these commands can reduce the
  capacity available to the other two. See [Rate limits](/rate-limits).
* Recording command acknowledgement events now document `expires_at` alongside
  `pull_url`. For mask and unmask acknowledgements, the two fields are either
  both present or both omitted. See
  [Command acknowledgements](/webhooks/command-accepted-events).
* A `503` response after an idempotent command may mean the command completed
  but its saved response could not be returned. Retry once with the same
  `Idempotency-Key`; if the response is still unavailable, reconcile using the
  resulting resource or webhook events before issuing a new key.
* WebSocket pause and resume affect audio in both directions. Pausing preserves
  buffered backend audio, and resuming does not change mute state.

### Fixed

* Playback seek requests now reject `seek_ms: 0`. Use a positive value to seek
  forward or a negative value to rewind.
* Authentication and client-error responses now distinguish malformed
  credentials (`400`), missing or invalid credentials (`401`), forbidden
  operations (`403`), and resources hidden by application ownership (`404`).
  Error responses expose a stable `code` for programmatic handling.