Zero-Shot Voice TTS
Upload a reference recording (audio, or a video with speech) plus a text, and get that text spoken in the reference speaker's voice. No voice training required — three seconds of clear speech is enough.
How it differs from "Voice Clone TTS": that endpoint uses the preset voices in the voice catalog; this one uses a reference you supply. The server automatically picks a clean 3–10 second single-speaker segment from the reference (separating vocals first when background music is present) and reports exactly which segment it used in report.ref.
⚠️ Zero-shot similarity depends heavily on reference quality. Prefer clear, dry (no reverb), single-speaker segments. The result resembles the speaker; it does not reach the tuned stability of a preset voice.
Create Task
Basics
| Item | Value |
|---|---|
| Method | POST |
| Path | /task/audio_tts_zero_shot |
| Content-Type | application/json |
| Auth | Authorization header (pass the API Key directly) |
Request Body
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
text | string | Yes | — | Text to synthesize; non-empty, up to 5000 characters (Unicode code points; one CJK character counts as 1) |
ref_file_id | string | Yes | — | File ID of the reference media (an uploaded audio or video file; only the audio track of a video is used). Total length must be between 3 seconds and 30 minutes, containing at least 3 seconds of continuous, clear, single-speaker speech; when background music is present the server separates vocals before picking the segment. By submitting this task you confirm that, per the User Agreement, you have obtained the separate consent of the person whose voice is being cloned and will not use the generated speech for impersonation or similar purposes |
ref_text | string | No | recognized server-side | Transcript of the reference segment. When omitted, the server runs speech recognition on the selected segment; if recognition fails or returns nothing the task fails (a wrong reference transcript drags the cloned voice off, so we fail rather than guess). When provided it is used verbatim with no recognition — recommended whenever you know what is being said. report.ref.text_source records which one was used |
ref_lang | string | No | same as text_lang | Language of the reference segment as a standard region language code: zh-CN, zh-HK (Cantonese), en-US, ja-JP or ko-KR; zh-CHS / zh-CHT are treated as zh-CN |
text_lang | string | No | zh-CN | Language of the text to synthesize, as a standard region language code from the same five; anything else returns a parameter error — no task is created and nothing is billed |
output_format | string | No | wav | Output audio format: wav or mp3 |
speed | number | No | 1.0 | Speech speed factor (1.0 = normal), valid range [0.5, 2.0]; out-of-range values return a parameter error and are never silently clamped |
fragment_interval | number | No | engine default | Pause between sentences in seconds, valid range [0.05, 1.0] (inclusive); out-of-range values return a parameter error and are never silently clamped |
subtitle_format | string | No | no subtitle | Pass srt to also receive a .srt subtitle file whose timings come from this run's per-sentence timeline and match the audio exactly; no extra charge. Same semantics as Voice Clone TTS |
canvas | integer[] | No | [1080, 1920] (portrait) | Output canvas [width, height], accepted only together with subtitle_format (sending it alone returns a parameter error). Overly long sentences are split into lines for this canvas; pass [1920, 1080] explicitly for landscape videos |
strip_punctuation | boolean | No | true | Punctuation stripping for the bonus .srt text only, accepted only together with subtitle_format. Same semantics as Voice Clone TTS |
Billing
Billed by the character count of the input text, in units of 1,000 characters, with exactly the same counting rules as Voice Clone TTS:
- Billable units =
textcharacter count ÷ 1000 (fractional units preserved); the final charge is rounded up to a whole credit, and any non-empty text costs at least 1 credit - The reference media's length is never billed: the same text costs the same whether the reference is 5 seconds or 20 minutes long
- The unit price is the "Zero-Shot Voice TTS" tier under the "Voice Clone TTS" family on the pricing page (currently 6 credits per 1,000 characters; the pricing page is authoritative)
Example Request
curl -X POST https://api.ai-mcn.tv:10000/task/audio_tts_zero_shot \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "Hello and welcome to this episode.",
"ref_file_id": "537489015178246",
"text_lang": "en-US",
"output_format": "wav",
"subtitle_format": "srt",
"canvas": [1920, 1080]
}'
Success Response
{
"code": 200,
"msg": "success",
"data": {
"task_id": "537489015178247",
"task_type": "audio_tts_zero_shot",
"status": "queued"
}
}
Query Task Result
Basics
| Item | Value |
|---|---|
| Method | GET |
| Path | /task/audio_tts_zero_shot/{task_id} |
| Auth | Authorization header (pass the API Key directly) |
Response (output_result)
Field names are identical to Voice Clone TTS, plus report.ref. Code that already reads that endpoint's output can be reused as is.
| Field | Type | Description |
|---|---|---|
file_id | string | Synthesized audio file ID |
download_url | string | Audio download path |
speaker | string | Always zero_shot (there is no preset voice code here; the key is kept so the output has the same shape as Voice Clone TTS) |
voice_id | string | Same as speaker |
engine | string | Synthesis engine |
sample_rate | integer | Audio sample rate (Hz) |
duration_ms | integer | Actual audio length in milliseconds; unrelated to billing |
segments_source | string | Where the per-sentence timing came from: assembled = accumulated from sentence-by-sentence synthesis; realigned = the assembled timing drifted from the audio and was re-aligned against the final audio; none = no usable timing this run (the segments key is then absent) |
segments | array | Per-sentence timing [{index, text, start_ms, end_ms}]: where each sentence starts and ends in the audio; end_ms includes the sentence-final pause and the timeline is contiguous. Absent when segments_source is none |
subtitle_file_id | string | Subtitle file (.srt) ID. Present only when subtitle_format was requested; empty string if generation failed, with the reason in errors.subtitle |
subtitle_file_download_url | string | Subtitle file download path |
errors | object | Present only when a bonus artifact was degraded. Subtitle failures are recorded under errors.subtitle — the task is still completed and the audio is unaffected |
report.ref | object | Report on the reference segment that was used (see below). Use it to decide whether to supply a different reference or your own ref_text |
report.ref fields
| Field | Type | Description |
|---|---|---|
span_ms | integer[] | Start and end, in milliseconds, of the segment actually used, relative to the original reference media — cut the same span from your file to verify |
separated | boolean | Whether vocal separation was applied: true = background music was detected and the segment comes from the separated vocals; false = clean speech, the original audio was used directly |
gain_db | number | Gain applied to the reference segment during normalization (dB) |
text_source | string | Where the reference transcript came from: user = your ref_text; asr = server-side recognition |
asr_confidence | number | Recognition confidence for the segment (0–1); when text_source is user it is the segment's recognition coverage, for reference only |
ref_text | string | The reference transcript actually used |
ref_lang | string | The reference language actually used (standard region code, e.g. en-US) |
Success Response
{
"code": 200,
"msg": "success",
"data": {
"task_id": "537489015178247",
"status": "completed",
"progress": 100,
"output_result": {
"file_id": "537489015178248",
"download_url": "/download/a1/output_tts.wav",
"speaker": "zero_shot",
"voice_id": "zero_shot",
"engine": "gpt_sovits",
"sample_rate": 32000,
"duration_ms": 5240,
"segments_source": "assembled",
"segments": [
{ "index": 0, "text": "Hello and welcome to this episode.", "start_ms": 0, "end_ms": 2600 },
{ "index": 1, "text": "Today we look at automatic dubbing.", "start_ms": 2600, "end_ms": 5240 }
],
"subtitle_file_id": "537489015178249",
"subtitle_file_download_url": "/download/a1/output_tts.srt",
"report": {
"ref": {
"span_ms": [3120, 11040],
"separated": false,
"gain_db": 4.2,
"text_source": "asr",
"asr_confidence": 0.93,
"ref_text": "hello everyone and welcome to today's show",
"ref_lang": "en-US"
}
}
},
"create_time": "2026-09-16T08:00:00Z",
"update_time": "2026-09-16T08:00:41Z"
}
}
Error Codes
| Code | HTTP | Description | Resolution |
|---|---|---|---|
6013 | 400 | Missing required parameter (text / ref_file_id) | Provide the parameter |
6016 | 400 | Invalid business parameter (empty or overlong text, text_lang / ref_lang outside the five supported languages, speed or fragment_interval out of range, invalid output_format, invalid subtitle parameters, reference media shorter than 3 seconds or longer than 30 minutes, etc.) | Fix per the parameter spec |
6014 | 400 | The reference file is not an audio or video file | Upload an audio or video file |
6004 | 404 | Reference file not found | Check ref_file_id |
6502 | 401 | Authentication failed | Check the Authorization header |
6201 | 402 | Insufficient quota | Top up in the dashboard |
6202 | 402 | Insufficient balance | Top up in the dashboard |
All of the above happen at task creation: no task is created and nothing is billed. Failures during reference preparation (for example no 3-second single-speaker segment can be found anywhere in the media, or the segment cannot be transcribed) happen during execution: the task ends as failed, the pre-deducted credits are refunded, and the reason is in the task's error message.
Limits
- Reference media: 3 seconds to 30 minutes, audio or video (only the audio track of a video is used). The server only picks 3–10 seconds from it; a longer file does not improve the result and only slows preprocessing — upload a clip that contains the target speaker.
- How the segment is picked: single speaker (no overlapping speech), recognition confidence above threshold, no silence longer than 0.6 seconds inside the segment, and a length of 3–10 seconds. If no candidate satisfies all four, the task fails and names the unmet criterion;
report.ref.span_mstells you which segment was finally used. - References with background music are vocal-separated first (
report.ref.separatedistrue); clean-speech references use the original audio directly to avoid the timbre loss separation can introduce. - Reference transcript: when you know what is being said, pass
ref_textyourself — it is more reliable than server-side recognition, and a wrong transcript noticeably hurts similarity. - Languages: both the reference and the target text are limited to the five standard codes
zh-CN/zh-HK/en-US/ja-JP/ko-KR. Cross-language use (for example a Chinese reference speaking English) works, with lower similarity than same-language use. - Every run is a new take: this endpoint never hits the synthesis cache (the reference differs every time), so identical requests are re-synthesized and billed as usual.
- One voice per task: a task clones a single speaker. If the reference contains a conversation, a single-speaker segment is picked; to clone several people, cut a reference per person and submit separately.
- Up to 5000 characters per request; the job shares the synthesis queue with the in-house voices of Voice Clone TTS, and long text is synthesized sentence by sentence and concatenated, so longer means slower.
- When you publish or distribute the generated speech, you must label it as AI-generated content in a clearly visible way, as required by law.
🤝 Join the Tonghe New Media Network to unlock internal member benefits: network members (internal) get custom-scope full-library material search (video / image / audio, including concept and non-commercial materials, with a commercial-only filter) and exclusive internal voices. Apply at the Creator Network; once approved, an administrator will enable internal access for you.