API: consent recordings are matched against the voice being cloned

Consent verification now checks who is speaking, not only what they said. A create whose consent_recording reads the phrase correctly but in a different voice from your sample is refused with 422 consent_speaker_mismatch and no voice is created.

This closes the gap the flow was always meant to close: the person consenting has to be the person being cloned, so permission relayed by somebody else - an account holder reading the phrase on a speaker’s behalf - does not pass.

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.

API: text is screened before synthesis

Text you send for synthesis is now screened before Speechify produces audio from it. A request whose content is not permitted returns 400 content_policy_violation with no audio, and is not billed. This applies to /v1/audio/speech, /v1/audio/stream, /v1/audio/stream/with-timestamps and /v1/audio/dialogue, and to an agent’s prompt and first_message when you create or update one.

API: `simba-3.2` voice cloning enters limited release

Cloned (personal) voices now synthesize on simba-3.2 for workspaces enabled for it, with no per-voice step. The earlier per-voice-key approval is gone: enablement is per workspace, and once yours is on, every clone you own works there. Contact us to be enabled.

Nothing else changes. The request and response are identical to a stock-voice call, and simba-3.2 remains English only, so a cloned voice with a non-English locale still returns 400 — use simba-3.0 for those. GET /v1/voices names simba-3.2 on your cloned voices once your workspace is enabled, so drive a picker off each voice’s models array rather than assuming. Cloning on simba-3.0, simba-english and simba-multilingual is unchanged.

API: `simba-3.0` is the new default TTS model

POST /v1/audio/speech, POST /v1/audio/stream and POST /v1/audio/stream/with-timestamps now resolve a request that omits model to simba-3.0 instead of the legacy simba-english. GET /v1/audio/models marks the change on its default flag.

Nothing you already send changes shape, and nothing that worked starts failing. A request that names a model explicitly is untouched - model: "simba-english" keeps getting Simba 1.6 English, and that model stays fully supported with nothing scheduled for removal.

Models list now reports per-model endpoints and curated-voice flag

GET /v1/audio/models now returns two new fields for each model:

  • endpoints — the synthesis routes this model may be passed to. Passing a model to an endpoint its endpoints list omits returns 400.
  • curated_voices — when true, only voices that explicitly name this model in their models array are accepted. When false, every catalogue voice works, including workspace clones.

API: Free tier gets a burst allowance on `/v1/audio/*`

The Free plan’s TTS rate limit no longer caps its burst bucket at the sustained rate. Previously Free was 1 request/second with a bucket capacity of 1, so a second request issued in the same second was rejected with 429. Free now gets a burst capacity of 10, so a normal opening burst of requests (a quickstart script, a first integration test) no longer trips the limiter.

API: canonical `Speechify-*` header names (legacy `X-` aliases still work)

Every header in Speechify’s public API surface now has one canonical, un-prefixed Speechify-* name (RFC 6648). The pre-2026 X--prefixed spellings are unaffected today - they’re still accepted on requests and still emitted on responses - and will keep working until 2027-07-24.

Legacy (still works until 2027-07-24)Canonical
X-Request-IDSpeechify-Request-Id
X-Speechify-Audio-Content-TypeSpeechify-Audio-Content-Type
X-RateLimit-Limit / -Remaining / -ResetRateLimit-Limit / -Remaining / -Reset
X-Speechify-SDK / X-Speechify-SDK-VersionSpeechify-SDK / Speechify-SDK-Version
X-Tenant-IDSpeechify-Tenant-Id

API: stream speech marks with `POST /v1/audio/stream/with-timestamps`

A new endpoint streams word-level speech marks alongside audio, so text highlighting, captions, and audio-text sync no longer need the batch POST /v1/audio/speech round trip. POST /v1/audio/stream is unchanged - same request body, still plain audio.

$curl -N -X POST https://api.speechify.ai/v1/audio/stream/with-timestamps \
> -H "Authorization: Bearer $SPEECHIFY_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "input": "Hello world.",
> "voice_id": "oliver",

API: `simba-3.0` now synthesizes six European languages

simba-3.0 is no longer English-only. It now officially supports English plus German, Spanish (Spain and Mexico), French, Italian and Brazilian Portuguese:

LanguageCode
Englishen-*
Germande-DE
Spanish (Spain)es-ES
Spanish (Mexico)es-MX
Frenchfr-FR
Italianit-IT
Portuguese (Brazil)pt-BR

Nothing changes in your request shape. Keep passing model: "simba-3.0" and set the language parameter to the language of your input; when you omit language, the voice’s own locale decides. English and non-English are served by two separate trainings behind the scenes, but that routing is internal, so the model ID you pass never changes.

API: filter `GET /v1/voices` by type, locale, gender, and model

GET /v1/voices now accepts four optional query filters:

FilterValuesDescription
typepersonal, sharedpersonal (the workspace’s cloned voices) or shared (the public catalogue). Omit to return both.
localeBCP-47 rangePrefix-matched and case-insensitive: en matches en-US and en-GB; en-US matches only en-US.
gendermale, female, not_specifiedOmit to return all genders.
modela model id, e.g. simba-3.2Voices that advertise the model in their models[]. Omit to return voices for all models.

API: published rate & concurrency limits, and a `docs_url` on 429s

The API limits reference now lists the per-plan rate limits (sustained requests per second, plus a burst allowance on Agents) and concurrency limits (simultaneous in-flight requests) for every plan, across both the audio (TTS) and Agents surfaces. Limits apply per account, not per API key.

429 Too Many Requests responses are now self-describing:

API: `simba-3.0` now supports cloned/personal voices

simba-3.0 now accepts cloned and personal voices on POST /v1/audio/speech and POST /v1/audio/stream. Pass a cloned voice’s voice_id with model: "simba-3.0", the same way you would with simba-english. Zero-shot clones (from a 10-30 second sample) are supported self-serve; fine-tuned voices remain on simba-english and simba-multilingual (contact sales).

API: cloned voices on `simba-3.2` (manual approval)

Cloned (personal) voices can now be synthesized on simba-3.2. Given the model’s quality bar, each cloned voice must first be reviewed and approved by Speechify — contact us to have a voice key approved for simba-3.2 — while we evaluate stronger safeguards. This is zero-shot cloning, gated only on that manual approval step.

simba-english and simba-multilingual continue to serve cloned voices self-serve, with no approval step and no change to existing integrations; simba-multilingual still speaks one cloned voice across 30+ languages. Once Speechify has approved a cloned voice key, pass it as voice_id with model: "simba-3.2".

API: list available TTS models with `GET /v1/audio/models`

GET /v1/audio/models returns the text-to-speech models you can pass as the model parameter, so you can populate a model picker at runtime instead of hardcoding the list.

1{
2 "models": [
3 { "id": "simba-english", "name": "Simba English", "default": true, "recommended": false, "description": "English-only synthesis; the model used when a request omits `model`.", "languages": ["en"] },
4 { "id": "simba-multilingual", "name": "Simba Multilingual", "default": false, "recommended": false, "description": "Synthesis across 30+ languages, including mixed-language input.", "languages": ["en", "fr-FR", "de-DE", "es-MX", ""] },
5 { "id": "simba-3.0", "name": "Simba 3.0", "default": false, "recommended": false, "description": "Earlier streaming-native model, English only. Superseded by simba-3.2.", "languages": ["en"] },
6 { "id": "simba-3.2", "name": "Simba 3.2", "default": false, "recommended": true, "description": "Streaming-native model with the lowest time-to-first-byte and richest expressivity, English only today.", "languages": ["en"] }

API: New `simba-3.2` streaming model (recommended)

simba-3.2 is now available on POST /v1/audio/speech and POST /v1/audio/stream via the model field. It is the go-forward Simba 3 model — streaming-native, with lower TTFB and richer expressivity than simba-3.0. We recommend simba-3.2 for new English integrations.

simba-3.2 serves from a curated voice allow-list. Pass one of its registered voice IDs as voice_id: beatrice_32, dominic_32, edmund_32, geffen_32, harper_32, hugh_32, imogen_32, wyatt_32.

API: voice-gender value `notSpecified` is now `not_specified`

The voice-gender enum value notSpecified is renamed not_specified so the gender vocabulary is consistent snake_case across the API. This affects the gender field on GET /v1/voices, GET /v1/voices/{voice_id}, and POST /v1/voices (request enum and response), and the male/female values are unchanged.

  • Before (pin 2026-06-27 or earlier): the unspecified gender is notSpecified.
  • After (2026-06-28+): the unspecified gender is not_specified.

API: `GET /v1/voices` returns an object envelope

GET /v1/voices now returns an object envelope instead of a bare JSON array, so the list can carry pagination and future sibling fields without another breaking change.

Before (pin 2026-06-26 or earlier): a bare array of voice objects.

After (2026-06-27+):

1{
2 "voices": [ { "id": "george", "display_name": "George", "...": "..." } ],
3 "next_cursor": null,
4 "has_more": false
5}

API version pinning with `Speechify-Version`

The API now supports date-based version pinning with the Speechify-Version request header.

  • Current version: 2026-06-25
  • Header format: YYYY-MM-DD
  • Resolution order: request header, workspace default, oldest supported version
  • Migration path: official SDKs pin their build-date version automatically; raw HTTP callers should send Speechify-Version explicitly.

Docs: response-streaming behaviour on `POST /v1/audio/stream` clarified

The documentation for POST /v1/audio/stream now describes the endpoint’s response shape accurately:

  • The response body is the raw audio bytes delivered over HTTP chunked transfer encoding. There is no JSON envelope and no Base64 encoding — that shape is what POST /v1/audio/speech returns.

  • The Accept header selects the container/codec. Each format’s response Content-Type and codec are now listed explicitly:

    AcceptResponse Content-TypeCodec
    audio/mpegaudio/mpegMP3, 64 kbps
    audio/oggaudio/oggOpus
    audio/aacaudio/aacAAC-LC
    audio/pcmaudio/L16; rate=24000; channels=1Raw 16-bit signed little-endian PCM
  • audio/pcm returns the IANA-registered audio/L16 type with rate and channels parameters per RFC 4856. Byte order is little-endian (industry convention, not the big-endian default the RFC specifies). The 200 response in the API reference now lists audio/L16 alongside audio/mpeg / audio/ogg / audio/aac.