PROMOWorld Cup is back – Get 20% extra credits on all Pro plans until July 31, 2026
Upgrade

🔒 Free tier data may be used to improve AI models. Upgrade Pro for 100% Privacy

TTS Forge Developer Documentation

REST API • Single TTS • Multi Voice • SRT to Speech

Tutorial Video

Tutorial Video

🎧 Live API Demo & Examples

Explore the TTS For Free API — test the live demo or view ready-to-use code samples in multiple languages.

Overview

TTSForFree exposes an asynchronous TTS pipeline. Create jobs by REST, then get the final audio by polling or callback depending on the flow.

  • 70+ languages and 1,800+ voices
  • Single TTS, multi-voice podcast style generation, and SRT-to-speech
  • User history APIs for single, voice-based, and merged jobs
  • Do not fetch audio before the job is marked SUCCESS

What This API Supports

This page covers the public user-facing TTS APIs currently available in the backend.

Single TTS

Convert one text input into one audio file through `CreateBy`, then poll `Status` or use `CallbackUrl`.

Multi Voice

Generate podcast or multi-speaker audio through `CreateMulti` with one `ConnectionId` and many blocks.

SRT to Speech

Generate dubbed audio from subtitle-style blocks with `StartMs` and `EndMs` through `CreateSrt`.

Realtime Updates

Some async flows return progress and final results over background processing, while the public docs below focus on the request and response contracts.

History APIs

Fetch single-job history, voice history, or merged-job history for the authenticated user account.

OpenAPI Specification

See the latest public schemas in Swagger.

Authentication

Send `X-API-Key` in every public request header.

To get your API key, open `/`. In the voice area there is a copy button you can use to copy the exact `Voice` value before calling the API. For history endpoints, also send `Authorization: Bearer YOUR_JWT` because those endpoints return the current user's own jobs.

Required Headers
X-API-Key: YOUR_API_KEY

Languages & Voices

Use these endpoints before generation so the frontend can show the current language, voice, and max-length limits.

`Pitch` is provider-dependent. Do not assume every voice supports it.

Get List Language
curl -X GET "https://api.ttsforfree.com/api/Common/GetListLanguage" \
  -H "X-API-Key: YOUR_API_KEY"
Get List Voice
curl -X GET "https://api.ttsforfree.com/api/Common/GetListVoice?lang=en&type=singlevoice" \
  -H "X-API-Key: YOUR_API_KEY"
Get Config Max Length
curl -X GET "https://api.ttsforfree.com/api/Common/GetConfigMaxLength" \
  -H "X-API-Key: YOUR_API_KEY"

Create Single TTS

Use `CreateBy` for one text input and one voice. `Pitch` is optional. `CallbackUrl` is optional.

`CreateBy` public DTO does not require `ConnectionId`.

cURL Request
curl --location "https://api.ttsforfree.com/api/TTS/CreateBy" \
  --header "X-API-Key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "Texts": "Hello everybody",
    "Voice": "v1:TldK3n9ei9wctuSlNYhG_cJ4UULVT8ZGjhxcuoaFow2hDTDsuTCuvaOYrVY",
    "Pitch": 0,
    "CallbackUrl": "https://your-app.com/api/tts/callback"
  }'
JSON Body
{
  "Texts": "Hello everybody",
  "Voice": "v1:TldK3n9ei9wctuSlNYhG_cJ4UULVT8ZGjhxcuoaFow2hDTDsuTCuvaOYrVY",
  "Pitch": 0,
  "CallbackUrl": "https://your-app.com/api/tts/callback"
}
Create Response
{
  "Id": 12345,
  "Message": "Proccessing",
  "Status": "PENDING",
  "Data": "",
  "ExpectUrl": "https://cdn.ttsforfree.com/20250606/abc.mp3",
  "ShareKey": "sha256..."
}

Check Single Status

Use the returned `Id` as your single-job id. Poll this endpoint if you are not using `CallbackUrl`.

If the request was served from cache, `Data` may already contain the final URL. Otherwise wait until `Status` becomes `SUCCESS`.

Status Request
curl -X GET "https://api.ttsforfree.com/api/TTS/Status/12345" \
  -H "X-API-Key: YOUR_API_KEY"
Status Response
{
  "Id": 12345,
  "Status": "SUCCESS",
  "Data": "https://cdn.ttsforfree.com/20250606/abc.mp3"
}

Create Multi Voice

Use `CreateMulti` for podcast-style or multi-speaker output. `ConnectionId` is required.

cURL Request
curl --location "https://api.ttsforfree.com/api/TTS/CreateMulti" \
  --header "X-API-Key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "ConnectionId": "signalr-connection-id",
    "MinSpeechRate": 0.95,
    "MaxSpeechRate": 1.50,
    "Blocks": [
      {
        "Texts": "Welcome to the show",
        "Voice": "v1:host_voice",
        "Volume": 1,
        "Speed": 1,
        "Pitch": 0,
        "PauseAfterMs": 300
      },
      {
        "Texts": "Thanks for inviting me",
        "Voice": "v1:guest_voice",
        "Volume": 1,
        "Speed": 1,
        "Pitch": 0,
        "PauseAfterMs": 500
      }
    ]
  }'
JSON Body
{
  "ConnectionId": "signalr-connection-id",
  "MinSpeechRate": 0.95,
  "MaxSpeechRate": 1.50,
  "Blocks": [
    {
      "Texts": "Welcome to the show",
      "Voice": "v1:host_voice",
      "Volume": 1,
      "Speed": 1,
      "Pitch": 0,
      "PauseAfterMs": 300
    },
    {
      "Texts": "Thanks for inviting me",
      "Voice": "v1:guest_voice",
      "Volume": 1,
      "Speed": 1,
      "Pitch": 0,
      "PauseAfterMs": 500
    }
  ]
}
Create Response
{
  "Id": 6789,
  "Message": "Success",
  "ExpectUrl": "https://cdn.ttsforfree.com/audio_merge/3f9b5a35-9ac4-4d51-a8fe-2e4d91523a88.mp3"
}

Create SRT to Speech

Use `CreateSrt` when each block already has subtitle timing. `ConnectionId` is required.

Gemini voices are currently not supported in SRT mode.

cURL Request
curl --location "https://api.ttsforfree.com/api/TTS/CreateSrt" \
  --header "X-API-Key: YOUR_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "ConnectionId": "signalr-connection-id",
    "MinSpeechRate": 0.95,
    "MaxSpeechRate": 1.50,
    "Blocks": [
      {
        "Texts": "Hello everyone",
        "Voice": "v1:voice_1",
        "Volume": 1,
        "Speed": 0.9,
        "Pitch": 0,
        "StartMs": 0,
        "EndMs": 1800
      },
      {
        "Texts": "Welcome back",
        "Voice": "v1:voice_1",
        "Volume": 1,
        "Speed": 0.9,
        "Pitch": 0,
        "StartMs": 2200,
        "EndMs": 4200
      }
    ]
  }'
JSON Body
{
  "ConnectionId": "signalr-connection-id",
  "MinSpeechRate": 0.95,
  "MaxSpeechRate": 1.50,
  "Blocks": [
    {
      "Texts": "Hello everyone",
      "Voice": "v1:voice_1",
      "Volume": 1,
      "Speed": 0.9,
      "Pitch": 0,
      "StartMs": 0,
      "EndMs": 1800
    },
    {
      "Texts": "Welcome back",
      "Voice": "v1:voice_1",
      "Volume": 1,
      "Speed": 0.9,
      "Pitch": 0,
      "StartMs": 2200,
      "EndMs": 4200
    }
  ]
}
Create Response
{
  "Id": 6790,
  "Message": "Success",
  "ExpectUrl": "https://cdn.ttsforfree.com/audio_merge/f0d4cb65-7d10-4f53-b930-1b231d2414d9.mp3"
}

Check Multi or SRT Status

Use the returned merged job `Id` from `CreateMulti` or `CreateSrt`.

Status Request
curl -X GET "https://api.ttsforfree.com/api/TTS/Multi/Status/6789" \
  -H "X-API-Key: YOUR_API_KEY"
Status Response
{
  "Id": 6789,
  "Status": "SUCCESS",
  "Data": "https://cdn.ttsforfree.com/audio_merge/3f9b5a35-9ac4-4d51-a8fe-2e4d91523a88.mp3"
}

Get Job Detail

For multi voice and SRT jobs, this endpoint returns the merged job and every child block audio record.

Use `FinalAudioUrl` for the merged file and `Blocks[].FilePath` for each block file.

Job Detail Request
curl -X GET "https://api.ttsforfree.com/api/TTS/GetJobTTSDetail?jobId=6789" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Authorization: Bearer YOUR_JWT"
Job Detail Response
{
  "Id": 1,
  "Message": "Success",
  "Data": {
    "Id": 6789,
    "TotalBlocks": 2,
    "StatusId": 200,
    "StatusName": "SUCCESS",
    "FinalAudioUrl": "https://cdn.ttsforfree.com/audio_merge/3f9b5a35-9ac4-4d51-a8fe-2e4d91523a88.mp3",
    "Blocks": [
      {
        "Id": 12345,
        "Text": "Welcome to the show",
        "Voice": "v1:host_voice",
        "FilePath": "https://cdn.ttsforfree.com/20250606/block1.mp3",
        "StatusId": 200
      }
    ]
  }
}

History APIs

History APIs are account-based. They return the authenticated user's own jobs, so include `Authorization: Bearer YOUR_JWT`.

Use `GetHistory` for single TTS jobs, `GetHistoryVoice` for a compact voice-focused history, and `GetHistoryMulti` for merged jobs. For SRT merged jobs, call `GetHistoryMulti` with `jobType=Srt`.

Get Single Job History
curl -X GET "https://api.ttsforfree.com/api/TTS/GetHistory?page=1&pageSize=10" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Authorization: Bearer YOUR_JWT"
Get Voice History
curl -X GET "https://api.ttsforfree.com/api/TTS/GetHistoryVoice?page=1&pageSize=10" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Authorization: Bearer YOUR_JWT"
Get Multi History
curl -X GET "https://api.ttsforfree.com/api/TTS/GetHistoryMulti?page=1&pageSize=10&jobType=Tts" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Authorization: Bearer YOUR_JWT"
Get SRT History
curl -X GET "https://api.ttsforfree.com/api/TTS/GetHistoryMulti?page=1&pageSize=10&jobType=Srt" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Authorization: Bearer YOUR_JWT"
History Response Example
{
  "Id": 1,
  "Message": "Success",
  "TotalRows": 1,
  "Data": [
    {
      "Id": 6789,
      "TotalBlocks": 2,
      "StatusId": 150,
      "StatusName": "MERGE_REQUESTED",
      "FinalAudioUrl": "",
      "Blocks": [
        {
          "Id": 12345,
          "Text": "Welcome to the show",
          "Voice": "v1:host_voice",
          "FilePath": "https://cdn.ttsforfree.com/20250606/block1.mp3",
          "StatusId": 200
        }
      ]
    }
  ]
}

Single-job Callback

If you pass `CallbackUrl` in `CreateBy`, the server POSTs a completion payload to your URL when the single TTS job finishes.

Current public callback behavior is for `CreateBy`. For multi voice and SRT, rely on the create and status endpoints documented above.

Callback Payload
POST https://your-app.com/api/tts/callback
Content-Type: application/json

{
  "Id": 12345,
  "Status": "SUCCESS",
  "Action": "ResponseTTSNotification",
  "FilePath": "https://cdn.ttsforfree.com/20250606/abc.mp3",
  "Data": "https://cdn.ttsforfree.com/20250606/abc.mp3",
  "Hash": "sha256...",
  "CompletedAt": "2026-06-06T10:10:10Z"
}

Rate Limits & Quotas

  • Call `GetConfigMaxLength` first if you want client-side validation before submit.
  • Multi voice and SRT requests are still validated per block and can fail even when the total screen looks valid.
  • Contact the team for higher limits or commercial usage.

Error Codes

Common Errors
400 Bad Request    // missing text, invalid block data, or invalid timeline
401 Unauthorized   // missing or invalid API key or user token
403 Forbidden      // quota exceeded or voice access not allowed
404 Not Found      // job id not found
429 Too Many       // rate limited
500 Server Error   // transient issue, retry with backoff

StatusId Meanings

These numeric values are the most important ones to explain in frontend docs when reading merged history or merged job detail data.

100

Waiting

Job has been accepted and is still waiting or pending in the processing pipeline.

150

Merging SRT / Merge Requested

Blocks are already being prepared and the merged audio file is being requested or assembled.

200

Success

The final audio is ready. At this point you can safely use `Data`, `ExpectUrl`, or `FinalAudioUrl`.

-100

Error

The job failed. Do not fetch the final audio URL until a new successful run is created.

FAQ

Frequently Asked Questions

Q: Should I use polling or another realtime method?

A: For the public docs, prioritize polling. Use `Status` for single TTS and `Multi/Status` for multi voice or SRT jobs. A simple interval such as every 5 seconds is usually enough for most frontend integrations.

Q: How long can a long video job take?

A: As a practical expectation, multi voice and SRT jobs for a long 2 to 3 hour video can often finish in around 5 minutes per job. Exact time still depends on block count, voice mix, and queue load.

Q: Any tips for better results?

A: If you are building longer workflows, start with `multi voice` and `srt` because they are the most flexible for long-form content. Split content into clean blocks, keep timing clear, and poll the job status instead of fetching output too early.

Q: What are the rate limits?

A: Free plans have lower limits per minute and per day. Paid plans have higher limits. The current limit policy can change by package, so handle 429 responses safely and contact the team if you need larger throughput.

Q: Where do I get the voice key?

A: Open the home page `/`. In the voice area there is a copy button for the voice key. You can test voices there first, then copy the exact `Voice` value into your API request.

Licensing & Terms

Free usage is suitable for testing and prototyping. For commercial usage, redistribution, or larger quotas, contact [email protected].