Skip to content

ElevenLabs Voice Design (/v1/text-to-voice) record + replay #452

Closed

Description

@tombeckenham

Summary

aimock records and replays ElevenLabs text-to-speech (onElevenLabsTTS), sound generation and music, but not Voice Design (/v1/text-to-voice/*). An app that designs a voice before speaking with it can't run hermetically: the design call either misses (strict mode fails) or goes to the real ElevenLabs account and bills it.

Checked against v1.42.0.

Routes

Method Path SDK call Notes
POST /v1/text-to-voice/design client.textToVoice.design(...) output_format is a query param. Returns previews[] of { generated_voice_id, audio_base_64, media_type, duration_secs, language } plus text.
POST /v1/text-to-voice client.textToVoice.create(...) Body { voice_name, voice_description, generated_voice_id }. Saves a take as a permanent voice and returns the voice object (voice_id, …). On the real API this uses up an account voice slot.

Example design body (@elevenlabs/elevenlabs-js):

{
  "voice_description": "A weathered sea captain in his sixties, gravelly, unhurried",
  "model_id": "eleven_ttv_v3",
  "auto_generate_text": true,
  "should_enhance": true,
  "guidance_scale": 25,
  "quality": 0.5
}

Suggested behaviour

  • Match design fixtures on voice_description (string or RegExp), like onElevenLabsTTS matches on text, e.g. mock.onElevenLabsVoiceDesign(/sea captain/, { previews: [...] }).
  • Save: replay should accept a generated_voice_id that a design fixture returned and hand back a stable voice_id, so a following /v1/text-to-speech/{voice_id} call can match an existing TTS fixture. It's fine if save isn't matched separately and just echoes a deterministic id.
  • Record: proxyAndRecord under the existing elevenlabs provider key. Worth noting: each preview's audio_base_64 is a full MP3 (usually 3 per call), so these fixtures will be much larger than JSON-only ones.
  • Nice to have: GET /v1/voices/{voice_id} and DELETE /v1/voices/{voice_id}. Apps that manage slots call them after saving (delete should be idempotent on 404).

Workaround today

mock.mount('/v1/text-to-voice', handler) with a hand-written Mountable. It works, but it bypasses the recorder and journal, so there's no record path.

Activity

  1. added 2 commits that reference this issue on Sep 15, 2026
    695fd67
    c9f4aa9
  2. added a commit that references this issue on Sep 16, 2026
    304050a
  3. added a commit that references this issue on Sep 16, 2026
    8566501
  4. added a commit that references this issue on Sep 22, 2026
  5. added a commit that references this issue on Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions