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, List a campaign’s contacts, List call scripts and List surveys.Breaking changes- A
cursorthe Dialer cannot decode is rejected instead of ignored. It now answers400withcode: "PAGINATION.INVALID_CURSOR". Until this release such a cursor was ignored and the endpoint returned200with the first page — the behaviour the 2026-09-02 entry below documented, and which that entry described as deliberate.
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 carries the full recipe.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 before that release rolls out.Breaking changes- An unfiltered campaign list no longer returns deleted campaigns.
Campaigns whose status is
deletedare excluded when you send nostatusfilter. 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 already promises: a deleted campaign drops out of the listings while its history stays available for reporting.
include_deleted=true— a new optional boolean query parameter, defaultfalse. Set it totrueand the list returns campaigns of every status,deletedincluded. Only the literal stringstrueandfalseare accepted; anything else is a400.status=deleted— unchanged, and still the way to list only deleted campaigns. Whenstatusis set,include_deletedhas no effect.
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.)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 a500, now come back as a clear 4xx. Check
your integration against the list below before that release rolls out.Breaking changes- A whitespace-only
nameis rejected.nameis now trimmed before it is validated on campaign, call-script and survey creates and updates, so" "is exactly as empty as""and answers400withname should not be emptyinsubErrors. It previously created a resource whose name rendered blank everywhere it was shown. schedule_policy.start_dateandstart_timeare format-pinned.start_datemust be a real calendar date inYYYY-MM-DD,start_timea validHH:MMorHH:MM:SS; anything else, including a date that does not exist such as2026-02-30, is a400naming the field, for exampleschedule_policy.start_date must be a real calendar date in YYYY-MM-DD. A31-12-2026typo 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,
filters.contactIdandfilters.userIdmust be1or greater, andfilters.dateFrom/filters.dateTomust be strict ISO 8601 — otherwise400. A window whosedateTois not after itsdateFromnow answers422withdateTo must be after dateFrom, and a bound that clears the strict ISO 8601 check but falls outside the published RFC 3339date-timeshape (the week date2026-W33, for one) answers422withdateFrom 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
404body 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 messageRoute not foundand acorrelationId. It no longer echoes an internal path or your query string back to you. Every error the Dialer service itself raises carries acorrelationId, this one included — errors answered before the request reaches the service, such as the auth layer’s401, do not.
- A malformed
jobIdis a400, not a500. Get an export job’s status and Get a download link for a completed export answer400withValidation failed (uuid is expected)and acorrelationIdwhenjobIdis not a UUID. Both operations now document that400.
- 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,deletedincluded. Passstatusif you need them left out. - Policy bundles are not stored verbatim. The
calling_policydescription 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_kindis a400, not a422. On Replace a campaign’s disposition buttons, enum and shape violations are400. The422is for atag_idthat is not a call tag on your account; a duplicatedtag_idis409. - Association ids are not checked for existence.
Replace a campaign’s associations
accepts any
ref_idfor 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.
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 documents the current contract.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 covers what MCP is, the tool profiles, and what each one is built for.
- Quickstart gets a client connected in five minutes.
- Tool reference lists every tool with its parameters, defaults and limits.
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.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/mcpthat 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.