How to Add Text-to-Speech to Your App with the Fish TTS API

How to Add Text-to-Speech to Your App with the Fish TTS API

If your product needs spoken output—voice notes, narrated lessons, support prompts, or generated media previews—the hard part is usually not calling a TTS model once. The hard part is designing an integration that can start simple, reuse voices when needed, handle longer text safely, and return an audio file your app can actually play.

What you can do

The Fish TTS endpoint on Ace Data Cloud exposes text-to-speech through a single HTTP API: POST https://api.acedata.cloud/fish/tts. With that endpoint, you can:

  • Turn a non-empty text string into an audio file.
  • Choose format values such as mp3, wav, or pcm; mp3 is the default, and pcm is returned in a WAV container.
  • Use a reusable saved or public voice through reference_id.
  • Use one-time instant voice cloning through references, without creating a long-term model.
  • Adjust speech delivery with prosody.speed and prosody.volume.
  • Send long-running work to a webhook with callback_url.

How it works

Requests are JSON over HTTPS. The required headers are authorization: Bearer {token} and content-type: application/json. The optional accept header may be set to application/json.

There is also an optional HTTP header named model. The documented options are s1, s2-pro, and s2.1-pro, with s2-pro as the default. The guide describes s2.1-pro as the latest generation, s2-pro as expressive, and s1 as more stable for long text.

A successful synchronous request returns an audio_url. That URL points to a CDN-hosted audio file that can be downloaded with GET or used directly in an HTML <audio> player.

Start with the smallest possible request

The safest first integration is a synchronous request with only text and format. This is useful for onboarding flows, short UI narration, product demos, or test fixtures in your application.

curl -X POST 'https://api.acedata.cloud/fish/tts'   -H 'authorization: Bearer {token}'   -H 'content-type: application/json'   -d '{
    "text": "Hello world.",
    "format": "mp3"
  }'

The response shape is intentionally small:

{
  "audio_url": "https://platform2.cdn.acedata.cloud/fish/e2ffcc06-18da-4a8c-b9aa-9337d0f9ec1d.mp3"
}

In a web app, you can store the URL with the generated object, attach it to a message, or play it immediately after the request completes.

Reuse a known voice with reference_id

When you already have a saved or public voice model, pass its ID as reference_id. The field accepts a string or an array of strings. It cannot be used at the same time as references.

curl -X POST 'https://api.acedata.cloud/fish/tts'   -H 'authorization: Bearer {token}'   -H 'content-type: application/json'   -d '{
    "text": "Hermanos míos, hoy es un buen día.",
    "reference_id": "8d2c17a9b26d4d83888ea67a1ee565b2",
    "format": "mp3"
  }'

This pattern is a good fit for product voices, character voices, course narrators, or any experience where consistency matters across many generated clips.

Clone a voice for one request

For temporary voice matching, use references. The documented shape is an array containing one object with audio and text. The audio must be a public HTTPS MP3 or WAV URL, and the transcript should match the reference audio accurately. The guide recommends reference audio between 10 and 270 seconds, while Studio uses a more conservative 10 to 60 seconds.

{
  "text": "新的旅程从这一刻开始,让我们一起向前。",
  "format": "mp3",
  "references": [{
    "audio": "https://platform2.cdn.acedata.cloud/fish/6220d605-39d0-4d43-9e58-0f12949dc9b9.mp3",
    "text": "春天的清晨,阳光穿过树叶,落在安静的小路上。"
  }]
}

Use this when you do not want to create a reusable model, or when every generation may use a different temporary voice. Avoid Base64, data URIs, credentialed URLs, and MessagePack here; the documented input is a public HTTPS audio URL.

Tune delivery with prosody and model headers

For app UI, small timing differences matter. The prosody object supports speed, where 1.0 is normal speech, and volume, measured as volume gain in dB. Positive volume values increase loudness; negative values reduce it.

curl -X POST 'https://api.acedata.cloud/fish/tts'   -H 'authorization: Bearer {token}'   -H 'content-type: application/json'   -H 'model: s1'   -d '{
    "text": "Faster speech with prosody overrides.",
    "prosody": { "speed": 1.2, "volume": 0 },
    "format": "mp3",
    "mp3_bitrate": 128
  }'

The mp3_bitrate field applies only when format is mp3, with documented values 64, 128, and 192. For browser stitching or downstream processing, the guide recommends pcm with a sample rate such as 16000.

Use callback_url for longer synthesis jobs

Long text can take several seconds or more. Instead of keeping a client connection open, pass callback_url. The immediate response includes task_id and started_at; later, the callback receives the final JSON result with the same task_id and an audio_url.

{
  "task_id": "79d82713-2897-4eeb-9934-e7544d471aa7",
  "audio_url": "https://platform2.cdn.acedata.cloud/fish/bd66b8c5-7543-4557-b684-baa72407e336.mp3"
}

That gives you a clean architecture: enqueue the synthesis, save the task ID, and update your database when the webhook arrives.

Handle failures explicitly

The documented errors include 400 token_mismatched for missing or invalid request parameters, 401 invalid_token for authentication issues, 429 too_many_requests for account rate limits, and 500 api_error for internal server errors. In practice, validate text before sending, keep format to documented values, and log any returned trace_id.

If you are adding TTS to a real product, start with the minimal request, add reference_id only when voice consistency becomes important, and move long text to callback_url before users start waiting on open HTTP connections. The full source guide is here: Fish TTS API Integration Guide.

Comments

Popular posts from this blog

Artistic QR Code API Integration Guidance

How to Configure Claude Code with CC Switch and Ace Data Cloud

How to Build a Server-Side Image Editing Workflow with GPT-Image-2