One Sume voice, a different language: the 409 and the confirm flag
Ask Sume TTS to speak Spanish with an English-tagged voice and you get a 409 before any charge. Retry with confirm_language_mismatch only if you mean it.

On Sume, a voice has one primary language, and TTS compares it to the language you request before creating a job. If they differ you get HTTP 409 tts_voice_language_mismatch with no job created and no charge. To speak across languages with one voice anyway, resend the same request with confirm_language_mismatch set to true.
What the guard does
The voice's primary language is stored as studio_agent_voices.language and set when a voice is created. The request's target comes from language on REST, or payload.language on MCP. The 409 returns the voice_id, voice_language and request_language so your client can show what clashed. Regional tags compare by primary language, so es and es-MX do not trigger it, and fil and tl count as the same language.
| Case | Result |
|---|---|
| Voice en, request en | Runs, no warning |
| Voice en, request es | 409 tts_voice_language_mismatch, no job, no charge |
| Same request plus confirm_language_mismatch: true | Runs |
| Voice es, request es-MX | Matches by primary language |
| Raw voice id with unknown library metadata | Can still be submitted |
In MCP the same check is a warning
tts_create returns a non-error tts_voice_language_warning result with confirmation_required set to true. The intended flow is to ask the person, then retry with the same idempotency key and confirm_language_mismatch true, without changing the voice, transcript or target language.
A safe retry pattern
In code, treat the 409 as a prompt rather than a failure. Read voice_language and request_language from the error body. If your own logic knows the mismatch is deliberate, retry once with confirm_language_mismatch true and the same idempotency key. If not, switch to a voice tagged with the target language, or fix the language field that you sent by mistake.
Sume's voice library tags sixteen languages: en, ko, ja, zh, es, fr, de, pt, it, hi, nl, pl, ru, sv, tr and tl. If your market is outside that list, check the catalog before you promise anything.
Should you override it?
Rarely for a real market. The guard exists because an English-tagged voice reading Spanish text is a common mistake, and the docs do not promise that a voice sounds native outside its tagged language. For a multilingual ad, pick a voice tagged for each language. Use the override for a deliberate case, such as a character who speaks with an accent, and listen before you ship.
Sources
Related posts
More in Developers
- Save a Sume artifact atomically: write a .part file, then rename
A half-written MP4 that looks finished is worse than none. Download a Sume artifact to a .part file, check the length, rename once. Tested in Python.
- Schedule the next Ideogram 4.5 batch wave from ratelimit-reset
Size each wave from ratelimit-remaining and wave_size_hint, and when the write bucket is empty sleep ratelimit-reset seconds. A pure function you can test.
- waitForJob threw SumeJobTimeoutError: resume polling with the job id
The Sume SDK stops waiting after 20 minutes by default, but the job keeps running. Catch SumeJobTimeoutError, read jobId and wait again. TypeScript example.
- SDK waitForJob after a 202 from createImage: TypeScript sample
When createImage returns 202 on a slow gpt-image-2.5 render, pass the job id to waitForJob from @sume-com/sdk and read the terminal job instead of hand-polling.
Written by Sume