> ## Documentation Index
> Fetch the complete documentation index at: https://developers.cloudtalk.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Changelog

> Updates to the CloudTalk API and developer documentation

<Update label="2026-09-07" description="A bad pagination cursor now returns 400" tags={["Dialer"]}>
  ## An undecodable pagination cursor is now a 400

  **This is a behaviour change**, shipping in the next Dialer release. It affects
  every cursor-paginated Dialer list:
  [List dialer campaigns](/api-reference/dialer/list-dialer-campaigns),
  [List a campaign's contacts](/api-reference/dialer/list-a-campaigns-contacts),
  [List call scripts](/api-reference/dialer/list-call-scripts) and
  [List surveys](/api-reference/dialer/list-surveys).

  **Breaking changes**

  * **A `cursor` the Dialer cannot decode is rejected instead of ignored.** It now
    answers `400` with `code: "PAGINATION.INVALID_CURSOR"`. Until this release
    such a cursor was ignored and the endpoint returned `200` with the first
    page — the behaviour the 2026-09-02 entry below documented, and which that
    entry described as deliberate.

  Why it changed: a restarted first page is indistinguishable from a genuine
  first page. A client paging until `meta.nextCursor` is `null` therefore read
  page one for ever when its stored cursor was truncated or mangled, and if it
  stopped, it recorded a partial sync as a complete one. A `400` makes that
  failure visible on the request that caused it.

  **Nothing changes for a correct paging loop.** Pass `meta.nextCursor` back
  exactly as you received it and you will never see this error. An **absent or
  empty** `cursor` is still not an error — it means "start from the first page".

  If you persist cursors between runs, treat the `400` as "my stored cursor is no
  longer usable": discard it and either restart the walk from a checkpoint you
  control, or fail the run so an operator can recover it. The
  [Pagination guide](/guides/pagination) carries the full recipe.
</Update>

<Update label="2026-09-03" description="Deleted campaigns hidden by default" tags={["Dialer"]}>
  ## Deleted campaigns leave the default campaign list

  **This is a behaviour change**, shipping in **Dialer release v1.0.22**. Check
  any code that pages through
  [List dialer campaigns](/api-reference/dialer/list-dialer-campaigns) before
  that release rolls out.

  **Breaking changes**

  * **An unfiltered campaign list no longer returns deleted campaigns.**
    Campaigns whose status is `deleted` are excluded when you send no `status`
    filter. Until v1.0.22 they were included, which is what the previous entry
    on this page documented — that was the behaviour at the time, and v1.0.22
    changes it so the list matches what
    [Delete a dialer campaign](/api-reference/dialer/delete-a-dialer-campaign)
    already promises: a deleted campaign drops out of the listings while its
    history stays available for reporting.

  Two ways to see deleted campaigns:

  * **`include_deleted=true`** — a new optional boolean query parameter,
    default `false`. Set it to `true` and the list returns campaigns of every
    status, `deleted` included. Only the literal strings `true` and `false` are
    accepted; anything else is a `400`.
  * **`status=deleted`** — unchanged, and still the way to list only deleted
    campaigns. When `status` is set, `include_deleted` has no effect.

  If your integration relied on deleted campaigns appearing in an unfiltered
  list, add `include_deleted=true` — or `status=deleted` if you only want the
  deleted ones — to those requests.

  Nothing else about the endpoint changed in v1.0.22: `cursor`, `limit`,
  `status` and `mode` behaved exactly as before, as did reading a single
  campaign by id. (`cursor` has since changed — see the 2026-09-07 entry
  above.)
</Update>

<Update label="2026-09-02" description="Dialer validation tightened" tags={["Dialer"]}>
  ## Stricter validation on the Dialer, and four corrections to these pages

  These changes ship in **Dialer release v1.0.21**. Requests the API used to
  accept, or used to fail on with a `500`, now come back as a clear `4xx`. Check
  your integration against the list below before that release rolls out.

  **Breaking changes**

  * **A whitespace-only `name` is rejected.** `name` is now trimmed before it is
    validated on campaign, call-script and survey creates and updates, so
    `"   "` is exactly as empty as `""` and answers `400` with
    `name should not be empty` in `subErrors`. It previously created a resource
    whose name rendered blank everywhere it was shown.
  * **`schedule_policy.start_date` and `start_time` are format-pinned.**
    `start_date` must be a real calendar date in `YYYY-MM-DD`, `start_time` a
    valid `HH:MM` or `HH:MM:SS`; anything else, including a date that does not
    exist such as `2026-02-30`, is a `400` naming the field, for example
    `schedule_policy.start_date must be a real calendar date in YYYY-MM-DD`. A
    `31-12-2026` typo used to be stored and silently left the campaign with no
    scheduled start at all.
  * **Export filters are validated.** On
    [Request a campaign data export](/api-reference/dialer/request-a-campaign-data-export),
    `filters.contactId` and `filters.userId` must be `1` or greater, and
    `filters.dateFrom` / `filters.dateTo` must be strict ISO 8601 — otherwise
    `400`. A window whose `dateTo` is not after its `dateFrom` now answers `422`
    with `dateTo must be after dateFrom`, and a bound that clears the strict
    ISO 8601 check but falls outside the published RFC 3339 `date-time` shape
    (the week date `2026-W33`, for one) answers `422` with
    `dateFrom must be a parseable ISO 8601 date-time`
    — in both cases **no job is enqueued**; such requests used to be accepted and
    complete with a header-only file that looked like "no data". Supplying only one bound is
    still valid: a missing end resolves to the time the job runs, a missing start
    to the campaign's creation.
  * **The unmatched-route `404` body changed.** A request to a path the Dialer
    does not route — `DELETE /v1/dialer/surveys/{surveyId}`, for instance — now
    answers the standard error envelope with the fixed message `Route not found`
    and a `correlationId`. It no longer echoes an internal path or your query
    string back to you. Every error the Dialer service itself raises carries a
    `correlationId`, this one included — errors answered before the request
    reaches the service, such as the auth layer's `401`, do not.

  **Fixes**

  * **A malformed `jobId` is a `400`, not a `500`.**
    [Get an export job's status](/api-reference/dialer/get-an-export-jobs-status)
    and
    [Get a download link for a completed export](/api-reference/dialer/get-a-download-link-for-a-completed-export)
    answer `400` with `Validation failed (uuid is expected)` and a
    `correlationId` when `jobId` is not a UUID. Both operations now document
    that `400`.

  **Corrections to these pages**

  Four things these pages claimed that the API does not do:

  * **[List dialer campaigns](/api-reference/dialer/list-dialer-campaigns)
    returns soft-deleted campaigns.** The page said they appear only when you
    filter with `status=deleted`. They do not: an unfiltered list returns every
    status, `deleted` included. Pass `status` if you need them left out.
  * **Policy bundles are not stored verbatim.** The `calling_policy` description
    said a bundle read back may carry knobs added by a newer release. Unknown
    keys are dropped on write, so only the documented knobs are ever stored.
  * **An unknown `outcome_kind` is a `400`, not a `422`.** On
    [Replace a campaign's disposition buttons](/api-reference/dialer/replace-a-campaigns-disposition-buttons),
    enum and shape violations are `400`. The `422` is for a `tag_id` that is not
    a call tag on your account; a duplicated `tag_id` is `409`.
  * **Association ids are not checked for existence.**
    [Replace a campaign's associations](/api-reference/dialer/replace-a-campaigns-associations)
    accepts any `ref_id` for an agent, target tag or queue group without
    verifying that it exists — a nonexistent target tag is stored and simply
    contributes no contacts. Validate the ids on your side.

  One clarification with no behaviour change at the time: a pagination `cursor`
  the Dialer cannot decode was **not** an error — the list restarted from the
  first page with `200`. **This no longer holds**: as of the 2026-09-07 entry
  above, such a cursor is a `400`. The
  [Pagination guide](/guides/pagination) documents the current contract.
</Update>

<Update label="2026-08-26" description="MCP documentation" tags={["Documentation", "MCP"]}>
  ## Connect AI assistants to CloudTalk

  The CloudTalk MCP server is documented. Connect Claude, Cursor, or any
  MCP-compatible client to your account and work with your calls, contacts and
  AI Voice Agents in natural language.

  * [Overview](/guides/mcp/overview) covers what MCP is, the tool profiles, and
    what each one is built for.
  * [Quickstart](/guides/mcp/quickstart) gets a client connected in five minutes.
  * [Tool reference](/guides/mcp/tools) lists every tool with its parameters,
    defaults and limits.

  MCP is available on the Essential plan and higher.
</Update>

<Update label="2026-08-25" description="Dialer authentication corrected" tags={["Dialer"]}>
  ## The Dialer partner API uses your standard API keys

  The Dialer endpoints (`https://api.cloudtalk.io/v1/dialer/*`) authenticate
  with the **same HTTP Basic credentials** as the rest of the API — your API
  Access Key ID as the username and API Access Key Secret as the password.

  These pages previously documented a separate per-company `x-api-key` header,
  provisioned on request. That scheme was never deployed: requests carrying an
  `x-api-key` header are rejected with `401`. If you could not authenticate
  against the Dialer endpoints before, use your standard key pair.

  Rate limiting on the Dialer surface is also **per company**, not per API
  key — a dedicated 60 requests-per-minute budget, separate from the core
  API's quota.

  Note the Dialer is a newly released product surface: depending on your
  account's rollout stage, campaigns managed through this API may not yet be
  visible in your CloudTalk Dashboard.
</Update>

<Update label="2026-08-20" description="New developer documentation" tags={["Documentation"]}>
  ## A new home for the CloudTalk API docs

  These docs run on a new platform. The API reference is generated from our
  OpenAPI specification, so what you read here is what the API serves.

  What you can do now:

  * **Send requests from the page.** Every endpoint has a playground. Fill in
    your own API keys and see the real response.
  * **Point your AI tools at the docs.** There is an MCP server at
    `https://developers.cloudtalk.io/mcp` that lets an assistant search these
    pages directly. Every page also has a **Copy page** menu that hands the
    content to ChatGPT, Claude, Cursor, VS Code or Perplexity.
  * Search across every page, and a dark mode that respects your system setting.

  This changelog starts here. From now on, changes to the API land as entries on
  this page, tagged by the part of the API they affect. Subscribe at
  [/changelog/rss.xml](https://developers.cloudtalk.io/changelog/rss.xml).
</Update>


## Related topics

- [How to Paginate CloudTalk API Collection Responses](/guides/pagination.md)
