API DocsAI Model APIsAudioFish Audio

Streaming TTS

Stream synthesized speech with word-level timestamp alignment snapshots for captions, karaoke, and timeline editing.

Stream text-to-speech with word/phrase-level timestamp alignment for karaoke highlighting, synced captions, and timeline editing.

The response is text/event-stream. Each SSE message contains a Base64 audio chunk and, when available, the latest cumulative alignment snapshot for that chunk_seq. Concatenate audio_base64 in arrival order. A newer snapshot for the same chunk_seq should replace the old snapshot — do not append segments.

Base URL

  • https://api.autorouter.top — Production

Authentication

BearerAuth: http (bearer) Authenticate using a Bearer Token. Format: Authorization: Bearer sk-xxxxxx

Endpoints

POST /fishaudio/v1/tts/stream/with-timestamp

Create Streaming TTS with Timestamps

The request header may set model: s1, s2-pro, s2.1-pro (default), s2.1-pro-free, drama-3-preview. Multi-speaker dialogue is supported only by the S2 series and drama-3-preview, not s1.

Request Body

Content-Type: application/json

Example:

{
  "text": "Hello! Welcome to Fish Audio.",
  "reference_id": "model-id",
  "format": "opus",
  "latency": "balanced"
}

Properties:

NameTypeRequiredDescription
textstringYesText to synthesize. For multi-speaker, switch with <|speaker:0|>, <|speaker:1|>
reference_idstring | string[] | nullNoVoice ID. A string for a single speaker; an array of IDs for multiple speakers
referencesobject[]NoInline reference audio for zero-shot cloning. Requires MessagePack; JSON cannot carry binary
formatstringNoOutput format: wav, pcm, mp3 (default), opus. Recommended: opus @ 48 kHz
latencystringNoLatency vs quality trade-off: normal (default, best quality), balanced, low. With balanced, long text may be split into multiple text chunks
prosodyobjectNoSpeed and volume
chunk_lengthintegerNoText chunk length, [100, 300]. Default 300
normalizebooleanNoWhether to normalize Chinese/English text (improves number reading stability). Default true
sample_rateinteger | nullNoSample rate (Hz). When null, format defaults apply: 44100 for most formats, 48000 for opus
mp3_bitrateintegerNoMP3 bitrate (kbps): 64, 128 (default), 192
opus_bitrateintegerNoOpus bitrate (bps). -1000 (default, auto), 24000, 32000, 48000, 64000
temperaturenumberNoExpressiveness, [0, 1]. Default 0.7. Higher is more diverse
top_pnumberNoNucleus sampling, [0, 1]. Default 0.7
max_new_tokensintegerNoMaximum audio tokens generated per text chunk. Default 1024
repetition_penaltynumberNoRepetition penalty. Values greater than 1.0 reduce repetition. Default 1.2
min_chunk_lengthintegerNoMinimum characters before splitting a new chunk, [0, 100]. Default 50
condition_on_previous_chunksbooleanNoWhether to use previous audio as context to keep the voice consistent. Default true
pronunciation_dictionaryobject[]NoUp to 3 pronunciation dictionaries (platform reference or inline; mutually exclusive)

prosodyobject(Optional)

Speed and volume adjustments.

speednumber(Optional)

Speed multiplier, [0.5, 2.0]. 1.0 is normal speed.

volumenumber(Optional)

Volume adjustment (dB). 0 is unchanged; positive is louder; negative is quieter.

normalize_loudnessboolean(Optional)

Whether to normalize loudness. Supported only by s2-pro and the S2.1-Pro series.

Responses

200: SSE stream

Content-Type: text/event-stream

401: Unauthorized

Content-Type: application/json

402: Insufficient balance

Content-Type: application/json

503: Service overloaded

Content-Type: application/json

Request Example

curl --no-buffer -X POST "https://api.autorouter.top/fishaudio/v1/tts/stream/with-timestamp" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer sk-xxxxxx" \
  -H "model: s2-pro" \
  -d '{
  "text": "Hello! Welcome to Fish Audio.",
  "reference_id": "model-id",
  "format": "opus",
  "latency": "balanced"
}'

Response Example

{
  "audio_base64": "SUQzBAAAAAAA...",
  "content": "Hello world",
  "chunk_seq": 0,
  "chunk_audio_offset_sec": 0.0,
  "alignment": {
    "audio_duration": 0.86,
    "segments": [
      {
        "text": "Hello",
        "start": 0,
        "end": 0.42
      },
      {
        "text": "world",
        "start": 0.42,
        "end": 0.86
      }
    ]
  }
}

Response fields:

NameTypeDescription
audio_base64stringOne Base64 audio chunk. Concatenate in arrival order to reconstruct the full audio. This is a transport chunk, not a sentence/word boundary
contentstringText described by the latest alignment snapshot in this event. Long input may be split into multiple content chunks
alignmentobject | nullLatest cumulative timestamp snapshot for this chunk_seq. When present, replace the old snapshot; do not append. null before the first snapshot or when unavailable
alignment.audio_durationnumberDuration of the audio generated for this text chunk, in seconds
alignment.segmentsobject[]Ordered text time segments
alignment.segments[].textstringSegment text
alignment.segments[].startnumberStart time in seconds relative to this text chunk's audio start
alignment.segments[].endnumberEnd time in seconds relative to this text chunk's audio start
chunk_seqintegerText chunk index that the alignment belongs to. Bucket snapshots by this value
chunk_audio_offset_secnumberAbsolute start of this text chunk in the full audio, in seconds. Add segment start/end to get the global timeline

Processing guidance:

  1. Concatenate every audio_base64 in order even when alignment is null.
  2. Store alignments in a map keyed by chunk_seq; each non-null alignment replaces that key.
  3. Add chunk_audio_offset_sec to each segment's local time to get global time.

Error Handling

HTTP 401 / 403 Auth Errors

  • 401 Unauthorized: API Key invalid or expired
  • 403 Forbidden: API Key has no access to this model (check token's model allowlist)

HTTP 402 Insufficient Balance

Returns insufficient user quota. Top up at the AutoRouter console.

HTTP 503 Service Overloaded

The server is under too much load to process the request. Retry later.

On this page