GET /v1/audio/voices

The exact contract for the Flux voice list: the response schema, how it is filtered by your key, entitlement values, ETag caching and errors.

Lists the speech voices your key can use. It makes no speech and is not billed. For a guided introduction, see Choose a voice.

EndpointGET https://api.fluxrouter.ai/v1/audio/voices
AuthAuthorization: Bearer <your Flux key> only; x-api-key is not read
PlanAny valid key
StatusLive

The same route also answers at /audio/voices, without the /v1. It works whether or not speech itself is switched on for your account.

Request

No body and no query parameters. Send If-None-Match with the ETag from an earlier response to get 304 when nothing has changed.

Response

json
{
  "object": "list",
  "data": [
    {
      "id": "coral",
      "model": "flux-voice-speak",
      "name": "Coral",
      "gender": "neutral",
      "description": "Standard voice",
      "languages": ["en"],
      "entitlement": "paid_cleared"
    }
  ]
}
FieldTypeMeaning
idstringThe voice id. Send it as voice in a speech request.
modelstringThe speech model this voice belongs to. Send it as model with this voice.
namestringA display name.
genderstringAs described for the voice, for example female, male or neutral.
descriptionstringA short description of the voice.
languagesarray of stringsLanguages the voice is described for, such as en, or multilingual.
entitlementstringpaid_cleared or premium_locked: whether this key can make speech now. The same for every row in one response.

Rows are sorted by model, then id. The response can carry other fields; do not depend on any field not listed here.

flux-voice-speak-hd takes a subset of the flux-voice-speak voices and has no rows of its own. Its voices are listed in the speech reference.

Filtering by key

The list holds only voices whose model is on your key's model list, which is the same list GET /v1/models returns for that key. Two keys on one account can see different voices if their model lists differ. Read the list with the key that will make the speech.

Caching

HeaderValue
ETagA hash of the response body
Cache-Controlprivate, no-cache
VaryAuthorization

Store the body and its ETag per key. Before each use, send the ETag back in If-None-Match. A 304 Not Modified has no body: keep your stored copy.

Errors

StatusBodyMeaning
401{"error": {"message": "Unauthorized"}}No Authorization: Bearer header, or the key was not accepted.
503{"error": {"message": "Voice catalogue unavailable"}}The list could not be built. Retry shortly.

Errors carry Cache-Control: no-store.

Example requests

bash
curl -i https://api.fluxrouter.ai/v1/audio/voices \
  -H "Authorization: Bearer $FLUX_API_KEY"
python
import requests

r = requests.get(
    "https://api.fluxrouter.ai/v1/audio/voices",
    headers={"Authorization": "Bearer sk-YOUR-FLUX-KEY"},
    timeout=30,
)
r.raise_for_status()
for voice in r.json()["data"]:
    print(voice["model"], voice["id"], voice["name"], voice["entitlement"])
ts
let etag: string | null = null;
let voices: unknown[] = [];

async function loadVoices() {
  const res = await fetch("https://api.fluxrouter.ai/v1/audio/voices", {
    headers: {
      Authorization: "Bearer sk-YOUR-FLUX-KEY",
      ...(etag ? { "If-None-Match": etag } : {}),
    },
  });
  if (res.status === 304) return voices;
  if (!res.ok) throw new Error(`voices: ${res.status}`);
  etag = res.headers.get("etag");
  voices = (await res.json()).data;
  return voices;
}