From 4f89f2211b8c90c8c32ecee7c65419447e62b3f5 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:05:37 +0000 Subject: [PATCH 1/3] docs: document TTS voice cloning --- skills/openrouter-tts/SKILL.md | 38 +++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/skills/openrouter-tts/SKILL.md b/skills/openrouter-tts/SKILL.md index c7f664e..f6341a9 100644 --- a/skills/openrouter-tts/SKILL.md +++ b/skills/openrouter-tts/SKILL.md @@ -55,12 +55,12 @@ echo "Saved $(realpath "$OUTPUT") (generation_id=${gen_id:-unknown})" ## Discovering TTS models and voices -Filter the models endpoint by output modality to list speech models. Each model carries a `supported_voices` array with the exact voice IDs that provider accepts. +Filter the models endpoint by output modality to list speech models. Each model carries a `supported_voices` array with the exact voice IDs that provider accepts. For voice cloning, also check `supports_voice_cloning`: send reference-audio requests only to endpoints that advertise it. ```bash # Models + voices in one shot curl -sS "https://openrouter.ai/api/v1/models?output_modalities=speech" \ - | jq '.data[] | {id, name, supported_voices, pricing}' + | jq '.data[] | {id, name, supported_voices, supports_voice_cloning, pricing}' # Just the voices for a specific model curl -sS "https://openrouter.ai/api/v1/models?output_modalities=speech" \ @@ -75,11 +75,43 @@ Voices are provider-namespaced: OpenAI uses short names (`alloy`, `nova`), Voxtr | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------- | | `model` | yes | TTS model slug (e.g. `openai/gpt-4o-mini-tts-2025-12-15`, `mistralai/voxtral-mini-tts-2603`). | | `input` | yes | The text to synthesize. | -| `voice` | yes | Voice identifier. Look up the exact set for your model in `supported_voices` on the models endpoint (see the discovery section above). Voices are provider-namespaced — e.g. `alloy` is an OpenAI voice and will not work on Voxtral or Kokoro. | +| `voice` | no* | Voice identifier. Look up the exact set for your model in `supported_voices` on the models endpoint (see the discovery section above). Voices are provider-namespaced — e.g. `alloy` is an OpenAI voice and will not work on Voxtral or Kokoro. Some models/providers require a voice; follow the endpoint's declared requirements. | | `response_format` | no | `mp3` or `pcm`. Default is `pcm`. **Set this explicitly** — the default is usually not what a user wants to save. | | `speed` | no | Playback multiplier (e.g. `1.25`). Honored by OpenAI TTS. Other providers may accept and ignore it, or reject unknown fields — check the provider's behavior if it matters. | +| `input_references` | no | Stateless voice cloning: one `input_audio` part with base64 or data-URI `data` and optional `format`, optionally followed by one transcript `text` part. The schema rejects more than one audio part or more than one transcript; send this only to endpoints with `supports_voice_cloning`. | | `provider` | no | Provider passthrough — see below. | +### Voice cloning + +Pass one reference-audio part, optionally accompanied by its transcript: + +```bash +curl -sS -X POST https://openrouter.ai/api/v1/audio/speech \ + -H "Authorization: Bearer $OPENROUTER_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "fish-audio/s1", + "input": "Welcome to the show.", + "input_references": [ + { + "type": "input_audio", + "input_audio": { + "data": "data:audio/wav;base64,", + "format": "wav" + } + }, + { + "type": "text", + "text": "Welcome to the show." + } + ], + "response_format": "mp3" + }' \ + --output cloned-voice.mp3 +``` + +The audio `data` may be raw base64 or a data URI. `format` is optional; most providers detect it from the audio bytes. Reference audio is limited to 20 MiB of base64 (15 MiB decoded), and `input_references` requires exactly one `input_audio` part plus at most one transcript part. + ### Picking a format - **`mp3`** (`audio/mpeg`) — compressed, ready to play in any audio app. Default choice for files the user will listen to or share. From f6bf605fff9d23ca9a5ae6a15d1017f5c030c523 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:06:05 +0000 Subject: [PATCH 2/3] docs: clarify TTS reference constraints --- skills/openrouter-tts/SKILL.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skills/openrouter-tts/SKILL.md b/skills/openrouter-tts/SKILL.md index f6341a9..bbfdba5 100644 --- a/skills/openrouter-tts/SKILL.md +++ b/skills/openrouter-tts/SKILL.md @@ -75,10 +75,10 @@ Voices are provider-namespaced: OpenAI uses short names (`alloy`, `nova`), Voxtr | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------- | | `model` | yes | TTS model slug (e.g. `openai/gpt-4o-mini-tts-2025-12-15`, `mistralai/voxtral-mini-tts-2603`). | | `input` | yes | The text to synthesize. | -| `voice` | no* | Voice identifier. Look up the exact set for your model in `supported_voices` on the models endpoint (see the discovery section above). Voices are provider-namespaced — e.g. `alloy` is an OpenAI voice and will not work on Voxtral or Kokoro. Some models/providers require a voice; follow the endpoint's declared requirements. | +| `voice` | no | Voice identifier. Look up the exact set for your model in `supported_voices` on the models endpoint (see the discovery section above). Voices are provider-namespaced — e.g. `alloy` is an OpenAI voice and will not work on Voxtral or Kokoro. Some models/providers require a voice; follow the endpoint's declared requirements. | | `response_format` | no | `mp3` or `pcm`. Default is `pcm`. **Set this explicitly** — the default is usually not what a user wants to save. | | `speed` | no | Playback multiplier (e.g. `1.25`). Honored by OpenAI TTS. Other providers may accept and ignore it, or reject unknown fields — check the provider's behavior if it matters. | -| `input_references` | no | Stateless voice cloning: one `input_audio` part with base64 or data-URI `data` and optional `format`, optionally followed by one transcript `text` part. The schema rejects more than one audio part or more than one transcript; send this only to endpoints with `supports_voice_cloning`. | +| `input_references` | no | Stateless voice cloning: one `input_audio` part with base64 or data-URI `data` and optional `format`, optionally accompanied by one transcript `text` part. The schema rejects more than one audio part or more than one transcript; send this only to endpoints with `supports_voice_cloning`. | | `provider` | no | Provider passthrough — see below. | ### Voice cloning @@ -110,7 +110,7 @@ curl -sS -X POST https://openrouter.ai/api/v1/audio/speech \ --output cloned-voice.mp3 ``` -The audio `data` may be raw base64 or a data URI. `format` is optional; most providers detect it from the audio bytes. Reference audio is limited to 20 MiB of base64 (15 MiB decoded), and `input_references` requires exactly one `input_audio` part plus at most one transcript part. +The audio `data` may be raw base64 or a data URI. `format` is optional; most providers detect it from the audio bytes. Reference audio is limited to 20 MiB of base64 (15 MiB decoded), and `input_references` requires one `input_audio` part plus at most one transcript part. ### Picking a format From 43db9938bc49fe4cde6680c4f5a3383714a06665 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2026 17:08:07 +0000 Subject: [PATCH 3/3] docs: discover TTS cloning per endpoint --- skills/openrouter-tts/SKILL.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/skills/openrouter-tts/SKILL.md b/skills/openrouter-tts/SKILL.md index bbfdba5..04b3e74 100644 --- a/skills/openrouter-tts/SKILL.md +++ b/skills/openrouter-tts/SKILL.md @@ -55,18 +55,25 @@ echo "Saved $(realpath "$OUTPUT") (generation_id=${gen_id:-unknown})" ## Discovering TTS models and voices -Filter the models endpoint by output modality to list speech models. Each model carries a `supported_voices` array with the exact voice IDs that provider accepts. For voice cloning, also check `supports_voice_cloning`: send reference-audio requests only to endpoints that advertise it. +Filter the models endpoint by output modality to list speech models. Each model carries a `supported_voices` array with the exact voice IDs that provider accepts. ```bash # Models + voices in one shot curl -sS "https://openrouter.ai/api/v1/models?output_modalities=speech" \ - | jq '.data[] | {id, name, supported_voices, supports_voice_cloning, pricing}' + | jq '.data[] | {id, name, supported_voices, pricing}' # Just the voices for a specific model curl -sS "https://openrouter.ai/api/v1/models?output_modalities=speech" \ | jq -r '.data[] | select(.id=="openai/gpt-4o-mini-tts-2025-12-15") | .supported_voices[]' ``` +Voice cloning support is an endpoint capability, not a models-list field. After choosing a model, inspect its provider endpoints via `GET /api/v1/models/{author}/{slug}/endpoints` and use reference audio only where `supports_voice_cloning` is `true`: + +```bash +curl -sS "https://openrouter.ai/api/v1/models/fish-audio/s1/endpoints" \ + | jq '.data.endpoints[] | {provider_name, model_id, supports_voice_cloning}' +``` + Voices are provider-namespaced: OpenAI uses short names (`alloy`, `nova`), Voxtral encodes language + persona + emotion (`en_paul_happy`), Kokoro prefixes with language/gender (`af_bella` = American female Bella). ## Parameters @@ -78,7 +85,7 @@ Voices are provider-namespaced: OpenAI uses short names (`alloy`, `nova`), Voxtr | `voice` | no | Voice identifier. Look up the exact set for your model in `supported_voices` on the models endpoint (see the discovery section above). Voices are provider-namespaced — e.g. `alloy` is an OpenAI voice and will not work on Voxtral or Kokoro. Some models/providers require a voice; follow the endpoint's declared requirements. | | `response_format` | no | `mp3` or `pcm`. Default is `pcm`. **Set this explicitly** — the default is usually not what a user wants to save. | | `speed` | no | Playback multiplier (e.g. `1.25`). Honored by OpenAI TTS. Other providers may accept and ignore it, or reject unknown fields — check the provider's behavior if it matters. | -| `input_references` | no | Stateless voice cloning: one `input_audio` part with base64 or data-URI `data` and optional `format`, optionally accompanied by one transcript `text` part. The schema rejects more than one audio part or more than one transcript; send this only to endpoints with `supports_voice_cloning`. | +| `input_references` | no | Stateless voice cloning: one `input_audio` part with base64 or data-URI `data` and optional `format`, optionally accompanied by one transcript `text` part. The schema rejects more than one audio part or more than one transcript; send this only to endpoints whose `supports_voice_cloning` capability is `true`. | | `provider` | no | Provider passthrough — see below. | ### Voice cloning