cicora.ai / docs
Audio API

Create speech (TTS)

Generate MP3 or PCM speech with a model and voice using the public API.

Last updated on

POST /v1/audio/speech accepts JSON and returns audio bytes. Authenticate with Authorization: Bearer and your workspace API key.

Generate MP3

Choose a model and voice from the Audio catalog. The example IDs below must be available in your deployment. The commands require curl and jq.

Terminal
export CICORA_API_KEY="sk_..."
export AUDIO_MODEL="speechkit-tts-general"
export AUDIO_VOICE="marina"

jq -n --arg model "$AUDIO_MODEL" --arg voice "$AUDIO_VOICE" '{
  model: $model,
  voice: $voice,
  input: "Hello! This is a short speech sample.",
  response_format: "mp3"
}' | curl --fail-with-body --silent --show-error \
  https://api.cicora.ai/v1/audio/speech \
  -H "Authorization: Bearer $CICORA_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- -D speech.headers -o speech.mp3

After a successful HTTP response, play speech.mp3. On an HTTP error, the output file can contain an error body; do not treat it as audio. The response uses audio/mpeg for MP3. JavaScript must read bytes, not call response.json():

speech.mjs
import { writeFile } from "node:fs/promises";

const response = await fetch("https://api.cicora.ai/v1/audio/speech", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CICORA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: process.env.AUDIO_MODEL,
    voice: process.env.AUDIO_VOICE,
    input: "Hello! This is a short speech sample.",
    response_format: "mp3",
  }),
});
if (!response.ok) throw new Error(`${response.status}: ${await response.text()}`);
await writeFile("speech.mp3", Buffer.from(await response.arrayBuffer()));

Request fields

FieldTypeBehavior
modelstring, requiredExact public Audio model ID supporting speech
inputstring or array, requiredNon-empty text, or turns with text, optional voice and instructions; arrays require multi-speaker support
voicestringPublic voice ID supported by this model; omission requires a compatible default voice
response_formatmp3 or pcmDefaults to pcm; select a published output profile
speedpositive numberMultiplier within the selected profile's minSpeed–maxSpeed range
instructionsstringDelivery instructions; best effort, omitted on routes without instruction support
input_referencesarrayReference content, only within the model's published reference limits
provider, session_id, user, traceobjects or stringsCommon Audio options

Check maxInputCharacters and maxInputBytes. Unknown fields and incompatible voice, format or reference combinations are rejected. Delivery instructions are an exception: a route without instruction support can generate speech while ignoring them. Check instructions in the model capabilities before relying on directed tone or emotion.

Voice and output combinations

After saving the catalog to audio-models.json and setting AUDIO_MODEL, inspect its verified voice profiles:

Terminal
jq --arg model "$AUDIO_MODEL" '
  .data[] | select(.id == $model) | .audio.profiles[]
  | select(.operation == "speech") | .profiles[]
  | {voice, voiceFamily, isDefault, format, sampleRateHz, channels, minSpeed, maxSpeed}
' audio-models.json

Changing a model can change the voice IDs, speed range and audio geometry. Use the exact public voice ID from a profile. Language support and sample recordings are visible in the cabinet's voice gallery.

PCM is signed 16-bit little-endian raw audio without a WAV header. Read X-Audio-Sample-Rate and X-Audio-Channels to configure playback or wrap it in a container; do not assume a universal 24 kHz rate. These headers also describe MP3 responses. The result uses Cache-Control: no-store.

References and multiple speakers

Models with multiSpeaker: true can accept turns. Reference parts use type: input_audio with input_audio.data or input_audio.url, type: text with text, or type: image_url with image_url.url. There can be at most three recordings, one transcript per recording and one image; a model can set lower limits or disable references. With multiple recordings, each transcript immediately follows its recording. Do not send references to models whose limits are zero.

Errors and interrupted audio

Before audio starts, validation failures return an HTTP error. Once bytes have been sent, a later failure closes the stream; it cannot replace the audio body with a JSON error. A partial file is not proof of a complete generation. See retry and billing behavior.

Troubleshooting

On this page