> This page is for Build.

> Append .md to any page URL for clean Markdown. Index: https://docs.speechify.ai/llms.txt.
>
> Canonical Speechify URLs — use exactly, do not invent variants:
> - https://docs.speechify.ai — this site (API reference, SDKs, quickstarts)
> - https://speechify.ai — marketing + product site
> - https://platform.speechify.ai — customer dashboard, signup, API keys, billing
> - https://api.speechify.ai — API base URL
> - https://github.com/Speechify-AI: GitHub org for the API (cookbook, demos, CLI). `github.com/speechify` does not exist.
> - https://status.speechify.ai — status + incidents
> - https://speechify.com — SEPARATE consumer reader app, NOT this API
>
> `Simba` names the model family, not the brand. Model ids: `simba-3.5` (48 languages under one id, English included; recommended), `simba-3.2` (English) and `simba-3.0` (English, German, Spanish, French, Italian and Portuguese; the default). `simba-english` and `simba-multilingual` are retired: a new workspace that sends either gets `400 model_retired`. `SimbaVoice` / `simbavoice.ai` are retired.
>
> Ask, don't scrape. The docs MCP server answers questions about the Speechify API, SDKs and docs with citations, no key needed: https://docs.speechify.ai/_mcp/server (Streamable HTTP, tool `searchDocs`). Setup: https://docs.speechify.ai/build/guides/get-started/connect-mcp

# API: voice cloning now verifies the speaker's consent

Creating a cloned voice now requires proof that the speaker agreed to it, in place of the `consent` object you used to send.

The flow adds one call in front of your existing create. `POST /v1/voices/consent-challenges` with the speaker's `full_name` returns a `phrase` and an `id`. Show the phrase to the speaker exactly as it comes back, record them reading it aloud, and send that recording as `consent_recording` with `consent_challenge_id` on `POST /v1/voices`. Speechify transcribes the recording, checks it against the phrase it issued, and keeps it as the consent record for that voice.

A challenge is single use, bound to your workspace, and short-lived, so create it when your speaker is ready to record rather than at the start of your flow. If it expires, create another one and record again.

**Update, 2026-09-23: that date arrived.** The unverified flow is switched off on every API version - see the [2026-09-23 entry](/build/changelog/2026/9/23) for the error it now returns and the two calls that replace it.

**The unverified flow is deprecated and will be switched off.** The date will be announced in this changelog and to affected workspaces ahead of time; plan for a window deliberately shorter than the [standard 12-month sunset](/build/guides/concepts/api-versioning), because an endpoint that clones a voice without checking the speaker agreed is a safety liability, not just an old shape. The new shape is `Speechify-Version: 2026-09-13`; it is callable now by pinning that version, and it becomes the default for new workspaces on that date. Until the switch-off, workspaces pinned to earlier versions keep the old `consent` object, and a pinned default does not move on its own: migrating means re-pinning `2026-09-13`. Existing cloned voices are unaffected and keep working, and synthesis endpoints are unchanged.

If you cannot migrate ahead of the switch-off, contact [support](mailto:support@speechify.ai) and we will work out an extension for your workspace.

One thing to know if you use an SDK: each release sends its own build date as the default version, so **upgrading to an SDK published on or after 2026-09-13 moves you to the new flow** even though your workspace is pinned to the old one. That is a deliberate break rather than a silent one - `consent_challenge_id` and `consent_recording` are required arguments on the new `create`, and the `consent` argument is gone, so the call stops building rather than failing at runtime. To upgrade the SDK without migrating yet, pass the version explicitly:

<Tabs>
  <Tab title="Python">
    ```python
    client = Speechify(token=os.environ["SPEECHIFY_API_KEY"], version="2026-08-07")
    ```
  </Tab>
  <Tab title="TypeScript">
    ```typescript
    const client = new SpeechifyClient({ token: process.env.SPEECHIFY_API_KEY, version: "2026-08-07" });
    ```
  </Tab>
  <Tab title="cURL">
    ```bash
    curl -H "Speechify-Version: 2026-08-07" ...
    ```
  </Tab>
</Tabs>

Migrating: `full_name` moves from the `consent` object onto the challenge call, `email` is dropped and nothing replaces it, and `consent_challenge_id` plus `consent_recording` become required.

The challenge itself can be refused before the recording is ever assessed. These do not share the 422 status, so branch on the code here too:

- **`404 consent_challenge_not_found`** — the `consent_challenge_id` does not resolve. A challenge minted for a different workspace answers with this same code and message, so a challenge id is never confirmed to exist by probing.
- **`409 consent_challenge_expired`** — the challenge is past its `expires_at`. Mint a new challenge and record again; the sample, the name, and the rest of the create are still good.
- **`409 consent_challenge_already_used`** — the challenge was already consumed. A challenge is single use, so this is also what a retry of a create whose response you never received returns: after a success, mint a fresh challenge rather than replaying the old one.
- **`502 consent_verification_unavailable`** — the verification backend could not answer. Nothing about the request is wrong, so this is transient — retry the same recording shortly.

Three of the new error codes share HTTP 422 and mean different things, so branch on the code rather than the status: `consent_phrase_mismatch` (the phrase was misread - read it again), `consent_speaker_mismatch` (the person in the recording is not the person in the sample - the speaker consenting has to be the speaker being cloned), and `consent_recording_unusable` (silence, too little speech, or an unreadable file - record it again). See [Consent](/build/guides/voice-cloning/consent) and the [Voice Cloning API](/build/voice-cloning-api).