How to Integrate and Test the Fish Audio S2 API
Fish Audio S2 API is a production-grade text-to-speech REST API powered by a 4-billion-parameter model trained on 10 million hours of audio. It supports voice cloning, streaming, and 50+ languages. This guide shows how to send requests, manage voice references, stream audio, and test each endpoint with Python and Apidog.
Introduction
Modern text-to-speech models can whisper, laugh, change tone mid-sentence, and generate multilingual speech. Fish Speech S2-Pro provides these capabilities through the Fish Audio S2 API.
A reliable integration requires more than a single POST request. You need to configure authentication, handle binary audio responses, manage reference audio, consume streaming data correctly, and test the API contract before deploying.
Before making your first request, download Apidog to inspect payloads, test emotion tags, validate streaming responses, and play generated audio directly from the response panel.
What Is the Fish Audio S2 API?
The Fish Audio S2 API is the HTTP interface to Fish Speech S2-Pro, an open-source TTS system built around a Dual-Autoregressive architecture.
The model separates:
- Semantic generation: a 4B-parameter autoregressive model operating along the time axis.
- Residual codebook generation: a 400M-parameter autoregressive model operating along the depth axis.
This architecture enables high-quality synthesis with a reported real-time factor of 0.195 on a single NVIDIA H200.
Core capabilities
| Feature | Details |
|---|---|
| Languages | Approximately 50, including English, Chinese, Japanese, Korean, Arabic, French, and German |
| Voice cloning | Uses 10–30 seconds of reference audio without fine-tuning |
| Emotion control | Natural-language tags such as [laugh], [whispers], and [super happy]
|
| Multi-speaker generation | Native `<\ |
| Streaming | Real-time chunked audio with {% raw %}"streaming": true
|
| Output formats | WAV, MP3, and PCM |
| Authentication | Bearer token through the Authorization header |
For a local deployment, the default base URL used in this guide is:
http://127.0.0.1:8080
API endpoints are available under the /v1/ namespace.
Set Up the Fish Audio S2 API
Prerequisites
You need:
- A deployed Fish Speech S2-Pro server.
- Model and decoder checkpoints.
- An API key.
- An HTTP client that can handle binary audio responses.
Start the API server
Run:
python tools/api_server.py \
--llama-checkpoint-path checkpoints/s2-pro \
--decoder-checkpoint-path checkpoints/s2-pro/codec.pth \
--listen 0.0.0.0:8080 \
--compile \
--half \
--api-key YOUR_API_KEY \
--workers 4
The relevant options are:
-
--compile: enablestorch.compileoptimization. This can substantially reduce inference latency but adds a one-time warmup cost. -
--half: enables FP16 to reduce GPU memory usage. -
--api-key: configures the Bearer token required by clients. -
--workers: configures the number of API workers.
Verify the server
Call the health endpoint:
curl http://127.0.0.1:8080/v1/health
Expected response:
{
"status": "ok"
}
If authentication is required for the health endpoint in your deployment, include the Bearer token:
curl \
-H "Authorization: Bearer YOUR_API_KEY" \
http://127.0.0.1:8080/v1/health
Configure the API in Apidog
Create a new HTTP project in Apidog, then configure an environment variable for the base URL:
http://127.0.0.1:8080
Add this global request header:
Authorization: Bearer YOUR_API_KEY
Saving authentication at the environment level avoids copying the token into every request. It also lets you switch between local, staging, and production environments without editing individual endpoints.
Send Your First TTS Request
The primary synthesis endpoint is:
POST /v1/tts
Test it with cURL
curl \
--request POST \
--url http://127.0.0.1:8080/v1/tts \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"text": "Hello! This is a test of the Fish Audio S2 API.",
"format": "wav",
"streaming": false,
"temperature": 0.8,
"top_p": 0.8,
"repetition_penalty": 1.1,
"max_new_tokens": 1024
}' \
--output output.wav
Play or inspect output.wav to verify the response.
Test it in Apidog
Create a POST request for:
http://127.0.0.1:8080/v1/tts
Set the body type to JSON and use:
{
"text": "Hello! This is a test of the Fish Audio S2 API.",
"format": "wav",
"streaming": false,
"temperature": 0.8,
"top_p": 0.8,
"repetition_penalty": 1.1,
"max_new_tokens": 1024
}
Send the request. The endpoint returns raw audio bytes. Apidog detects the audio response and provides an inline player, allowing you to verify the generated speech without writing client code.
TTS request parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
text |
string | Required | Text to synthesize |
format |
string | "wav" |
Output format: wav, mp3, or pcm
|
chunk_length |
integer | 200 |
Synthesis chunk size, typically 100–300
|
seed |
integer | null |
Fixed seed for reproducible output |
streaming |
boolean | false |
Returns audio in real-time chunks |
max_new_tokens |
integer | 1024 |
Maximum number of tokens to generate |
temperature |
float | 0.8 |
Sampling randomness, typically 0.1–1.0
|
top_p |
float | 0.8 |
Nucleus sampling threshold, typically 0.1–1.0
|
repetition_penalty |
float | 1.1 |
Penalizes repeated sequences, typically 0.9–2.0
|
use_memory_cache |
string | "off" |
Controls in-memory reference encoding cache |
Clone a Voice with Reference Audio
Fish Audio S2 supports zero-shot voice cloning. Provide a short reference audio clip and a matching transcript, then use the resulting reference ID in later TTS requests.
Only use reference audio that you have permission to process and clone.
Encode the reference audio
The request expects base64-encoded audio. Encode a WAV file with Python:
import base64
from pathlib import Path
audio_bytes = Path("reference.wav").read_bytes()
audio_base64 = base64.b64encode(audio_bytes).decode("utf-8")
Path("reference.txt").write_text(audio_base64)
Add the reference
Send a request to:
POST /v1/references/add
Example body:
{
"id": "my-voice-clone",
"text": "This is the reference transcription matching the audio.",
"audio": "<base64-encoded-wav-bytes>"
}
Expected response:
{
"success": true,
"message": "Reference added successfully",
"reference_id": "my-voice-clone"
}
In Apidog, create the request with a JSON body and replace the audio value with the encoded audio data.
Generate speech with the reference
Pass the stored reference_id to /v1/tts:
{
"text": "This sentence will be spoken in the cloned voice.",
"reference_id": "my-voice-clone",
"format": "mp3"
}
Save this request as a reusable template when testing multiple voices. You can then compare different references by changing only reference_id.
Test the Fish Audio S2 API with Python
API contract tests catch problems such as:
- Missing or deleted reference IDs.
- Invalid sampling parameters.
- Incorrect content types.
- Empty or truncated audio.
- Authentication failures.
- Streaming responses consumed incorrectly.
Install the test dependencies:
python -m pip install pytest httpx
Set the API configuration through environment variables:
export FISH_AUDIO_BASE_URL="http://127.0.0.1:8080"
export FISH_AUDIO_API_KEY="YOUR_API_KEY"
On PowerShell:
$env:FISH_AUDIO_BASE_URL = "http://127.0.0.1:8080"
$env:FISH_AUDIO_API_KEY = "YOUR_API_KEY"
Create test_fish_audio_s2_api.py:
import base64
import os
from pathlib import Path
import httpx
BASE_URL = os.getenv("FISH_AUDIO_BASE_URL", "http://127.0.0.1:8080")
API_KEY = os.environ["FISH_AUDIO_API_KEY"]
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
class TestFishAudioS2API:
"""API contract tests for Fish Audio S2 endpoints."""
def test_health_check(self):
response = httpx.get(
f"{BASE_URL}/v1/health",
headers=HEADERS,
timeout=10,
)
assert response.status_code == 200
assert response.json()["status"] == "ok"
def test_tts_returns_wav_audio(self):
payload = {
"text": "Unit test: verifying Fish Audio S2 API output.",
"format": "wav",
"seed": 42,
}
response = httpx.post(
f"{BASE_URL}/v1/tts",
json=payload,
headers=HEADERS,
timeout=60,
)
assert response.status_code == 200
assert response.headers["content-type"].startswith("audio/wav")
assert len(response.content) > 1000
def test_tts_rejects_invalid_temperature(self):
payload = {
"text": "Test invalid temperature.",
"temperature": 99.0,
}
response = httpx.post(
f"{BASE_URL}/v1/tts",
json=payload,
headers=HEADERS,
timeout=30,
)
assert response.status_code == 422
def test_reference_lifecycle(self):
reference_id = "unit-test-voice"
audio_path = Path("test_reference.wav")
audio_base64 = base64.b64encode(
audio_path.read_bytes()
).decode("utf-8")
try:
add_response = httpx.post(
f"{BASE_URL}/v1/references/add",
json={
"id": reference_id,
"text": "This is a unit test reference audio.",
"audio": audio_base64,
},
headers=HEADERS,
timeout=30,
)
assert add_response.status_code == 200
assert add_response.json()["success"] is True
list_response = httpx.get(
f"{BASE_URL}/v1/references/list",
headers=HEADERS,
timeout=30,
)
assert list_response.status_code == 200
assert reference_id in list_response.json()["reference_ids"]
finally:
httpx.request(
"DELETE",
f"{BASE_URL}/v1/references/delete",
json={"reference_id": reference_id},
headers=HEADERS,
timeout=30,
)
Place a valid audio fixture named test_reference.wav in the same directory, then run:
pytest test_fish_audio_s2_api.py -v
Using a fixed seed makes the sampling configuration reproducible. Avoid asserting that the entire audio file is byte-for-byte identical unless your deployment guarantees deterministic output across its hardware and software configuration.
Run Automated Tests in Apidog
You can run the same endpoint checks through Apidog's Test Scenarios feature:
- Open your Fish Audio S2 API collection.
- Select Test Scenarios.
- Create a new scenario.
- Add requests in this order:
- Health check.
- TTS request.
- Add reference.
- List references.
- Delete reference.
- Add assertions to the TTS request:
- Response status equals
200. -
Content-Typecontainsaudio. - Response body is not empty.
- Response time is below your chosen threshold.
- Response status equals
- Run the scenario and inspect the result for each step.
For the reference flow, extract the created reference ID or use a dedicated test ID. Always include a delete request so test data does not accumulate between runs.
Apidog reports assertion results and response timings, allowing the scenario to be reused during development or as part of a CI-triggered API test workflow.
Stream Audio in Real Time
For live playback, set "streaming": true and consume the response incrementally.
import os
import httpx
base_url = os.getenv(
"FISH_AUDIO_BASE_URL",
"http://127.0.0.1:8080",
)
api_key = os.environ["FISH_AUDIO_API_KEY"]
with httpx.stream(
"POST",
f"{base_url}/v1/tts",
json={
"text": "Streaming audio from the Fish Audio S2 API in real time.",
"format": "wav",
"streaming": True,
},
headers={
"Authorization": f"Bearer {api_key}",
},
timeout=None,
) as response:
response.raise_for_status()
with open("streamed_output.wav", "wb") as audio_file:
for chunk in response.iter_bytes(chunk_size=4096):
if chunk:
audio_file.write(chunk)
The server begins returning audio before synthesis is complete. The reported time-to-first-audio is approximately 100ms, making streaming suitable for interactive voice applications.
When integrating streaming into an application:
- Call
raise_for_status()before processing chunks. - Ignore empty chunks.
- Do not load the entire response into memory.
- Use
timeout=Noneor a timeout appropriate for long synthesis requests. - Confirm that your playback layer supports the selected audio format.
Add Inline Emotion Control
Emotion and delivery instructions are included directly in the text field:
{
"text": "[whispers] The secret is hidden here. [super happy] I found it!",
"format": "wav"
}
No additional request parameter is required. The model interprets supported bracketed tags as prosody instructions.
Examples from the Fish Speech source include:
[laugh]
[cough]
[pitch up]
[professional broadcast tone]
[whisper in small voice]
Test tags individually before combining them. This makes it easier to determine whether an unexpected result comes from a specific instruction or from the interaction between multiple tags.
Integration Checklist
Before shipping a Fish Audio S2 integration, verify the following:
- [ ] The API key is stored outside source control.
- [ ] The health endpoint is monitored.
- [ ] TTS requests have explicit client timeouts.
- [ ] Binary responses are written or streamed without text decoding.
- [ ] The response
Content-Typematches the requested format. - [ ] Reference audio has a matching transcript.
- [ ] Reference IDs are created, listed, and deleted correctly.
- [ ] Invalid parameters return expected validation errors.
- [ ] Streaming clients handle partial and empty chunks.
- [ ] Test references are removed after automated test runs.
- [ ] Voice cloning is limited to audio you are authorized to use.
Conclusion
The Fish Audio S2 API exposes text-to-speech, zero-shot voice cloning, emotion control, and real-time streaming through a REST interface.
A reliable implementation should:
- Configure Bearer authentication at the client or environment level.
- Validate binary audio responses and content types.
- Manage the full reference lifecycle.
- Consume streaming responses incrementally.
- Maintain automated tests for both valid and invalid requests.
Use Apidog to send requests, inspect and play binary audio responses, save reusable API examples, and run automated endpoint scenarios without first building a custom test interface.
FAQ
What is the Fish Audio S2 API?
The Fish Audio S2 API is the REST interface to Fish Speech S2-Pro, a 4B-parameter text-to-speech model trained on 10 million hours of audio. It supports voice cloning, streaming, emotion control, and 50+ languages through endpoints under /v1/.
How do I authenticate?
Send a Bearer token in the request headers:
Authorization: Bearer YOUR_API_KEY
The server API key is configured at startup through the --api-key option. In Apidog, store the token at the environment level so it is automatically included in requests.
Can I test the API without writing test code?
Yes. Apidog Test Scenarios can send requests and validate status codes, headers, response times, and request sequences through a visual interface.
For repeatable CI checks, you can also use the pytest and httpx test suite shown above.
Which audio formats are supported?
The API returns WAV, MP3, or PCM audio. Select the output through the format field:
{
"text": "Generate this as MP3.",
"format": "mp3"
}
WAV is the default.
How does voice cloning work?
Upload a 10–30 second reference clip and its matching transcript to:
POST /v1/references/add
Then pass the returned ID to /v1/tts:
{
"text": "Generate speech using the stored voice.",
"reference_id": "my-voice-clone"
}
The API clones the voice without additional fine-tuning.
What is the reported real-time factor?
On a single NVIDIA H200, Fish Audio S2 reports a real-time factor of 0.195 with streaming enabled. This corresponds to generating approximately five seconds of audio per second of compute. Reported time-to-first-audio is approximately 100ms.
How do I inspect audio responses in Apidog?
When the API returns binary audio, Apidog renders an inline audio player. You can listen to the result, inspect response headers, and add assertions from the same request panel.
Top comments (0)