Skip to navigation

Migrating to verified voice-cloning consent

Move from the consent field to the consent-challenge flow, pinned to Speechify-Version 2026-09-13

Creating a cloned voice now proves the speaker agreed, in place of the consent object you used to send. If your integration still posts a consent form field to POST /v1/voices, this page moves you to the verified consent-challenge flow. The change was announced in the changelog.

The old consent form field was switched off on 2026-09-23, for every workspace and every API version. A POST /v1/voices that still sends a consent string (JSON with fullName and email) and no challenge returns 400 consent_verification_required, whatever Speechify-Version it pins. Migrate to the consent-challenge flow below. The window was deliberately shorter than the standard 12-month sunset, because cloning a voice without checking the speaker agreed is a safety liability, not just an old shape; the date was announced in the changelog. Existing cloned voices are unaffected.

What is changing

Consent used to be an assertion — a consent object carrying the speaker’s fullName and email. It is now verified: the speaker reads a phrase we issue, and you send that recording as the consent record.

Old (version 2026-08-07 and earlier)New (version 2026-09-13)
Proof of consentconsent form field: { "fullName": …, "email": … }A consent challenge the speaker reads aloud
POST /v1/voices fieldsconsentconsent_challenge_id + consent_recording (both required); consent is gone
Calls to clone a voiceone (POST /v1/voices)two (POST /v1/voices/consent-challenges, then POST /v1/voices)

A pinned default never moves on its own, so migrating means re-pinning Speechify-Version: 2026-09-13. Workspaces created on or after that date are on the verified flow already.

Are you affected?

You are affected if POST /v1/voices sends a consent form field. If your create already sends consent_challenge_id and consent_recording, you are on the new flow — nothing to do.

The new flow

Cloning is now two calls: a consent leg that proves agreement, then the create you already make.

When your speaker is ready to record, create a challenge with their full_name. It returns a phrase and an id.

POST
/v1/voices/consent-challenges
from speechify import Speechify
client = Speechify(
token="YOUR_TOKEN_HERE",
)
client.voices.consent_challenges.create(
idempotency_key="a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
full_name="Jane Doe",
)

Show the phrase to the speaker exactly as it comes back and record them reading it aloud. A challenge is single use, bound to your workspace, and short-lived — create it at record time, not at the start of your flow. If it expires, create another and record again.

2. Create the voice with the recording

Send the recording as consent_recording alongside consent_challenge_id. Speechify transcribes it, checks it against the phrase it issued, and keeps it as the voice’s consent record.

POST
/v1/voices
from speechify import Speechify
client = Speechify(
token="YOUR_TOKEN_HERE",
)
client.voices.create(
idempotency_key="a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
sample="example_sample",
avatar="example_avatar",
consent_recording="example_consent_recording",
)

What moves, what’s gone

  • full_name moves from the old consent object onto the challenge call.
  • email is dropped — nothing replaces it.
  • consent_challenge_id and consent_recording become required on POST /v1/voices.
  • The endpoint, your existing voice ids, and every synthesis call are unchanged.

Handle the new refusals

Three new errors share HTTP 422, so branch on the code, not the status:

CodeMeansFix
consent_phrase_mismatchThe phrase was misreadHave the speaker read it again
consent_speaker_mismatchThe recording isn’t the voice being clonedThe consenting speaker must be the one being cloned
consent_recording_unusableSilence, too little speech, or an unreadable fileRecord it again

One more, on HTTP 400: consent_verification_required means the create still sent the old consent field and no challenge. The fix is this guide.

If you use an SDK

Each SDK release sends its own build date as the default version. An SDK published on or after 2026-09-13 takes consent_challenge_id and consent_recording as required arguments and has no consent argument, so the call stops compiling until it is migrated rather than failing at runtime. Pinning an older version does not bring the old flow back: it was switched off for every version.

Migration checklist

1

Re-pin the version

Set Speechify-Version: 2026-09-13 (or pass it to your SDK client). A pinned default does not move on its own.

3

Send the recording on create

Replace the consent field with consent_challenge_id and consent_recording. Drop email — it has no replacement.

4

Handle the 422s

Branch on consent_phrase_mismatch, consent_speaker_mismatch, and consent_recording_unusable.

See also