Simba 3.2 and the models endpoint: what changed and how to migrate

simba-3.2 is Speechify's streaming-native English TTS model, and GET /v1/audio/models lets you discover models at runtime instead of hardcoding a list. Since 21 October 2026 the recommended model is simba-3.5. What shipped, which voices 3.2 serves, and how to move.

Updated 8 min read
The Simba 3.2 sculpture, a satin silver wave crest, beside the headline Simba 3.2, streaming-native English speech. Below it: find every model at runtime with GET /v1/audio/models.
The Simba 3.2 sculpture, a satin silver wave crest, beside the headline Simba 3.2, streaming-native English speech. Below it: find every model at runtime with GET /v1/audio/models.

simba-3.2 was our recommended model for new English integrations until 21 October 2026, when Simba 3.5 took the recommendation. It’s streaming-native English. Two changelog entries landed a day apart to support it: simba-3.2 itself on July 8, and GET /v1/audio/models on July 9, a discovery endpoint so you never hardcode a model list again. This post covers what shipped, the one real constraint (English-only), and how to move an existing simba-3.0 integration over.

If you want to follow along with real requests, grab an API key. Every response below is from a live call.

What shipped

simba-3.2 works on the two synthesis endpoints of the Text-to-Speech API you already use, POST /v1/audio/speech and POST /v1/audio/stream, by passing "model": "simba-3.2".

The second entry is the more structural one. GET /v1/audio/models returns the model catalog, so your code can ask the API which models exist and which one to prefer, rather than shipping a hardcoded string that goes stale. Here is the real response for a new workspace on 30 September 2026, trimmed to the fields that matter:

{
  "models": [
    {
      "id": "simba-3.0",
      "name": "Simba 3.0",
      "default": true,
      "recommended": false,
      "deprecated": false,
      "description": "Streaming-native model serving both English and multilingual synthesis under one id: English, German, Spanish, French, Italian and Portuguese, routed by the request `language`. The default when a request omits `model`.",
      "languages": ["en", "de-DE", "es-ES", "es-MX", "fr-FR", "it-IT", "pt-BR"]
    },
    {
      "id": "simba-3.2",
      "name": "Simba 3.2",
      "default": false,
      "recommended": true,
      "deprecated": false,
      "description": "Streaming-native model with the lowest time-to-first-byte and richest expressivity, English only today. Serves every English voice in the catalog, your workspace's own cloned voices included. Use `simba-3.0` for any other language.",
      "languages": ["en"]
    }
  ]
}

Since 21 October 2026 the same call also returns simba-3.5, and it carries the recommended flag. Two flags do the work. recommended: true marks the model to reach for, currently simba-3.5. default: true is the model the API uses when a request omits model, which is simba-3.0. Read that pairing carefully: if you don’t set model, you get the default, not the recommended one. Setting model explicitly is the whole migration in one sentence, and the rest of this post is the detail around it.

What “streaming-native” means for latency

TTFB is time to first byte: how long after you send the request until the first chunk of audio comes back. For a file you generate once and play later, optimise total time. For anything a person waits on, a voice reply or a read-aloud that starts on click, optimise TTFB.

Time to first byte

Where the first audio byte lands

Both endpoints synthesize the same clip. The difference is when you get the first byte. POST /v1/audio/speech returns the whole file at once, so the first byte is also the last. POST /v1/audio/stream sends audio in chunks, so playback can start while the rest is still being generated.

  1. Full synthesisPOST /v1/audio/speech
  2. StreamingPOST /v1/audio/stream

For a file you download and play later, the total time is what matters and the two are close. For anything a person waits on, TTFB is the number, and streaming is what keeps it low. simba-3.2 is streaming-native, so its TTFB is the lowest of the lineup.

POST /v1/audio/speech synthesizes the whole clip and returns it in one JSON response, base64-encoded. POST /v1/audio/stream returns raw audio bytes over chunked transfer encoding, so the first bytes arrive while the rest is still being generated. A June 23 clarification pinned down exactly what the stream endpoint returns per Accept header:

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

All of them are 24 kHz mono. The audio/pcm row is the one that trips people up: you ask for audio/pcm and the response labels itself audio/L16, which is the IANA-registered name for that raw format. Sending Accept: audio/pcm to the stream endpoint with model: simba-3.5 on 16 October 2026 read the response header back as audio/L16;rate=24000;channels=1, the same as simba-3.2. For the browser path, the Web Audio streaming post plays these chunks as they land.

Which voices simba-3.2 serves, and what happens off-language

simba-3.2 is English-only. It serves every English voice in the catalogue, built-in voices like beatrice_32, dominic_32, edmund_32, geffen_32, harper_32, hugh_32, imogen_32 and wyatt_32 plus your own cloned voices, but no non-English voice.

Point a non-English voice at simba-3.2 and you get a 400 bad_request, not audio, with a message that names simba-3.0 as the model for that voice. Its models array won’t list simba-3.2 either.

A voice’s models array in GET /v1/voices lists which models it supports, so filter your voice picker by that array and a user can’t select a pairing the API will reject.

Stop hardcoding models: a runtime model picker

The point of GET /v1/audio/models is to pick a model by its properties, not its name. Fetch the list, keep the models that speak your language, and prefer recommended, falling back to default. That’s one small function, and it keeps working when the recommended model changes under you.

In TypeScript:

async function pickModel(language = "en"): Promise<string> {
  const res = await fetch("https://api.speechify.ai/v1/audio/models", {
    headers: { Authorization: `Bearer ${process.env.SPEECHIFY_API_KEY}` },
  });
  if (!res.ok) throw new Error(`GET /v1/audio/models failed: ${res.status}`);
  const { models } = await res.json();

  const forLanguage = models.filter((m) =>
    m.languages.some((l: string) => l === language || l.startsWith(`${language}-`)),
  );

  const recommended = forLanguage.find((m) => m.recommended);
  const fallback = forLanguage.find((m) => m.default) ?? models.find((m) => m.default);
  return (recommended ?? fallback).id;
}

The same shape in Python:

import os
import requests

def pick_model(language: str = "en") -> str:
    res = requests.get(
        "https://api.speechify.ai/v1/audio/models",
        headers={"Authorization": f"Bearer {os.environ['SPEECHIFY_API_KEY']}"},
    )
    res.raise_for_status()
    models = res.json()["models"]

    for_language = [
        m for m in models
        if any(l == language or l.startswith(f"{language}-") for l in m["languages"])
    ]

    recommended = next((m for m in for_language if m["recommended"]), None)
    fallback = next((m for m in for_language if m["default"]), None) or next(
        (m for m in models if m["default"]), None
    )
    return (recommended or fallback)["id"]

Since 21 October 2026, either one returns simba-3.5 for any of its 48 languages, because it carries the recommended flag; pass the primary subtag the catalog lists, such as ja. A language no model lists falls through to the default, simba-3.0, so the catalog can grow with no code change.

Migrating a simba-3.0 integration

If you’re already calling simba-3.0, the move to simba-3.5 is small:

  • Change the model field on your speech or stream call from simba-3.0 to simba-3.5. If you’d rather not hardcode it again, drop in the picker above.
  • Keep your voice_id: simba-3.5 takes every voice in the catalog in all 48 of its languages, which include all six of simba-3.0’s. Set language on any request whose text is not in the voice’s own language.
  • If you’re a raw HTTP caller (not on an SDK), pin Speechify-Version so a later wire change doesn’t move you unexpectedly. The version pinning post covers the header; the SDKs send it for you.

simba-3.0 and simba-3.2 stay available and aren’t deprecated, so you can move one call at a time. What changed in Simba 3.5 is in its launch post.

The Python and Node paths are the same call you already make, just with the model swapped, so the Python streaming post and the Node.js TTS post both apply unchanged.

FAQ

simba-3.5, since 21 October 2026. It’s flagged recommended: true in GET /v1/audio/models and speaks 48 languages under one model id on every plan. simba-3.2, streaming-native English, and simba-3.0, English plus German, Spanish, French, Italian and Portuguese, stay available and are not deprecated.

Do I have to change my code to use simba-3.2?

Set the model field to simba-3.2 on your POST /v1/audio/speech or POST /v1/audio/stream call, and make sure your voice_id is one the model supports. If you omit model entirely, the API falls back to the default, simba-3.0, not simba-3.2. So yes: pick the model explicitly, either as a literal or via the models endpoint.

Why did my simba-3.2 request return a 400?

Most likely a non-English voice. simba-3.2 serves every English voice in the catalogue (cloned voices included) but is English-only, so a non-English voice returns 400 bad_request with a message naming the fix. Check the voice’s models array in GET /v1/voices; for a language simba-3.2 doesn’t cover, use simba-3.5, which takes every catalog voice in 48 languages.

What does GET /v1/audio/models return?

A models array. Each entry has an id (the string you pass as model), a name, boolean default and recommended flags, a deprecated flag, a description, and a languages list. Read recommended to pick the model to reach for and default to know what a request without a model field resolves to. Fetching it at runtime means you don’t hardcode a model list that goes stale when a new model lands.

Is simba-3.0 deprecated now that simba-3.2 exists?

No. simba-3.0 is not deprecated, and it stays the default when a request omits model. The older Simba 1.6 lineup, simba-english and simba-multilingual, is retired from API version 2026-09-21: a new workspace that sends either gets a 400 model_retired. Since 21 October 2026 the recommended model is simba-3.5.

The model reference and the full parameter surface are in the Speechify docs.

Privacy preferences

Choose what we may store on this device. You can change this at any time from the footer.

Strictly necessary

Sign-in, security, load balancing, and remembering your privacy choices. These cannot be switched off.

Always on

Analytics

How the site is used in aggregate - which pages get read, where people get stuck - so we can improve it.

Marketing

Measures which campaigns bring people here, and lets us show relevant ads on other platforms.