> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://developers.omicx.one/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://developers.omicx.one/_mcp/server.

# Chuyển văn bản thành giọng nói

POST https://api.omicx.one/tts
Content-Type: application/json

Nhận một đoạn văn bản và trả về link file audio đọc nội dung đó, xử
lý đồng bộ.

**Backpressure:** hệ thống giới hạn tối đa 18 request TTS xử lý đồng
thời — nếu đạt giới hạn, trả về `503 SERVICE_OVERLOADED` kèm
`Retry-After: 2`.

**Circuit breaker:** nếu nhà cung cấp lỗi 5 lần trong 10 lần gọi gần
nhất, circuit breaker mở trong 30 giây — trong lúc này mọi request
nhận `503 AI_PROVIDER_UNAVAILABLE` kèm `Retry-After` là số giây còn
lại.


Reference: https://developers.omicx.one/integrations/text-to-speech/create-speech

## Request

### Headers

- `X-Api-Key` (string, required)
- `Idempotency-Key` (string, optional) — Key tuỳ chọn, tự sinh phía client, giúp request tính phí retry an toàn. Gửi lại nguyên vẹn cùng một giá trị khi retry: lần gọi thành công đầu tiên được tính phí một lần, kết quả được replay lại cho các lần gọi sau với cùng key (trong vòng 24 giờ). Gửi lại trong lúc request gốc vẫn đang xử lý sẽ nhận `409 DUPLICATE_REQUEST`.

### Body (application/json)

This endpoint expects a TtsRequest.

- `text` (string, required) — Văn bản cần đọc.
- `voiceId` (string, required) — Mã giọng đọc — lấy tại `GET /tts/voices`. Bắt buộc.
- `modelId` (string, required) — Mã model dùng để tạo giọng nói — lấy tại `GET /tts/models`. Bắt buộc; `modelId` ngoài danh sách model hợp lệ sẽ bị từ chối với `400`.
- `languageCode` (string, optional) — Gợi ý ngôn ngữ, ví dụ `vi`. Dành cho tương lai — provider hiện bỏ qua trường này.
- `config` (map from string to any, optional, nullable) — Tham số cấu hình tuỳ chọn cho model đã chọn — một tập con của field `config` trả về tại `GET /tts/models` (ví dụ `speed`, `speechEmotion`, `speechStyle`, `age` tuỳ model, đặt tên dạng camelCase). Được chuyển thẳng cho nhà cung cấp AI, **không** được xác thực (validate) ở tầng public-service — giá trị `speed`/option không hợp lệ sẽ bị nhà cung cấp từ chối. Chỉ những tham số được gửi mới bị ghi đè; tham số bỏ trống dùng giá trị mặc định của provider.

## Response

### 200

Thành công.

- `trackingId` (string, required) — Mã tra cứu request, dùng khi cần đối soát phí, liên hệ hỗ trợ, hoặc tra cứu lại qua `GET /tts/jobs`.
- `audioUrl` (string, required) — URL tải file audio đã tổng hợp — trỏ tới endpoint tải xuống self-host của public-service (`GET /tts/audio`), KHÔNG phải link CDN của nhà cung cấp. File được lưu trữ tối đa 30 ngày, URL sống đủ theo vòng đời file.
- `audioDuration` (double, required) — Độ dài âm thanh đầu ra (giây).
- `fileSizeBytes` (long, required) — Dung lượng file audio đầu ra (byte), đo phía server.
- `processingTimeMs` (long, required) — Tổng thời gian xử lý end-to-end (mili-giây).
- `languageCode` (string, optional, nullable) — Mã ngôn ngữ đã gửi khi tổng hợp — có thể `null` nếu không gửi.

## Errors

### 400 Bad Request Error

`VALIDATION_ERROR` — dữ liệu đầu vào sai (ví dụ `text` trống/quá 10.000 ký tự, hoặc `modelId` không tồn tại).

- `error` (ErrorResponseError, optional)

### 401 Unauthorized Error

`API_KEY_REQUIRED` hoặc `API_KEY_INVALID` — thiếu, sai, hoặc key đã bị thu hồi/hết hạn.

- `error` (ErrorResponseError, optional)

### 403 Forbidden Error

`INSUFFICIENT_SCOPE` — key hợp lệ nhưng thiếu scope `tts:execute`.

- `error` (ErrorResponseError, optional)

### 409 Conflict Error

`DUPLICATE_REQUEST` — retry khi request idempotent gốc vẫn đang xử lý.

- `error` (ErrorResponseError, optional)

### 429 Too Many Requests Error

`RATE_LIMIT_EXCEEDED` hoặc `QUOTA_EXCEEDED`.

- `error` (ErrorResponseError, optional)

### 502 Bad Gateway Error

`AI_PROVIDER_ERROR` — nhà cung cấp trả lỗi hoặc response không hợp lệ.

- `error` (ErrorResponseError, optional)

### 503 Service Unavailable Error

`SERVICE_OVERLOADED` hoặc `AI_PROVIDER_UNAVAILABLE` — thử lại sau `Retry-After`.

- `error` (ErrorResponseError, optional)

## Types

### ErrorResponseError

- `code` (string, optional) — Nhóm lỗi (dạng máy đọc được), ổn định theo từng HTTP status.
- `subCode` (string, optional) — Mã cụ thể, ổn định — dùng để phân nhánh xử lý / dịch i18n. Hãy xử lý logic dựa trên `subCode`, không dựa vào chuỗi `message`.
- `message` (string, optional) — Mô tả cho con người đọc (dùng để debug), không nên dịch trực tiếp.
- `timestamp` (datetime, optional)
- `path` (string, optional) — Đường dẫn request đầy đủ.
- `details` (list of ErrorResponseErrorDetailsItems, optional) — Chỉ xuất hiện khi `code` là `VALIDATION_ERROR` — danh sách lỗi theo từng trường.

### ErrorResponseErrorDetailsItems

## Examples

### default

**Response**

```json
{
  "trackingId": "018f8b3c-6d1b-7a2c-8e4f-5b6c7d8e9f0a",
  "audioUrl": "https://api.omicx.one/tts/audio?k=MDE5ZjY4ZmE...",
  "audioDuration": 3.4,
  "fileSizeBytes": 68432,
  "processingTimeMs": 512,
  "languageCode": "vi"
}
```

**SDK Code**

```python default
import requests

url = "https://api.omicx.one/tts"

headers = {"X-Api-Key": "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"}

response = requests.post(url, headers=headers)

print(response.json())
```

```javascript default
const url = 'https://api.omicx.one/tts';
const options = {method: 'POST', headers: {'X-Api-Key': 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go default
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://api.omicx.one/tts"

	req, _ := http.NewRequest("POST", url, nil)

	req.Header.Add("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby default
require 'uri'
require 'net/http'

url = URI("https://api.omicx.one/tts")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'

response = http.request(request)
puts response.read_body
```

```java default
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.omicx.one/tts")
  .header("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  .asString();
```

```php default
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.omicx.one/tts', [
  'headers' => [
    'X-Api-Key' => 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  ],
]);

echo $response->getBody();
```

```csharp default
using RestSharp;

var client = new RestClient("https://api.omicx.one/tts");
var request = new RestRequest(Method.POST);
request.AddHeader("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
IRestResponse response = client.Execute(request);
```

```swift default
import Foundation

let headers = ["X-Api-Key": "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]

let request = NSMutableURLRequest(url: NSURL(string: "https://api.omicx.one/tts")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Model flash-v1 (chỉ hỗ trợ speed)

**Request**

```json
{
  "text": "Xin chào, đây là bản demo từ OMICX",
  "voiceId": "EGvMuAim33",
  "modelId": "flash-v1",
  "config": {
    "speed": 1
  }
}
```

**Response**

```json
{
  "trackingId": "018f8b3c-6d1b-7a2c-8e4f-5b6c7d8e9f0a",
  "audioUrl": "https://api.omicx.one/tts/audio?k=MDE5ZjY4ZmE...",
  "audioDuration": 3.4,
  "fileSizeBytes": 68432,
  "processingTimeMs": 512,
  "languageCode": "vi"
}
```

**SDK Code**

```python Model flash-v1 (chỉ hỗ trợ speed)
import requests

url = "https://api.omicx.one/tts"

payload = {
    "text": "Xin chào, đây là bản demo từ OMICX",
    "voiceId": "EGvMuAim33",
    "modelId": "flash-v1",
    "config": { "speed": 1 }
}
headers = {
    "X-Api-Key": "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Model flash-v1 (chỉ hỗ trợ speed)
const url = 'https://api.omicx.one/tts';
const options = {
  method: 'POST',
  headers: {
    'X-Api-Key': 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    'Content-Type': 'application/json'
  },
  body: '{"text":"Xin chào, đây là bản demo từ OMICX","voiceId":"EGvMuAim33","modelId":"flash-v1","config":{"speed":1}}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Model flash-v1 (chỉ hỗ trợ speed)
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.omicx.one/tts"

	payload := strings.NewReader("{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"flash-v1\",\n  \"config\": {\n    \"speed\": 1\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Model flash-v1 (chỉ hỗ trợ speed)
require 'uri'
require 'net/http'

url = URI("https://api.omicx.one/tts")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"flash-v1\",\n  \"config\": {\n    \"speed\": 1\n  }\n}"

response = http.request(request)
puts response.read_body
```

```java Model flash-v1 (chỉ hỗ trợ speed)
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.omicx.one/tts")
  .header("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  .header("Content-Type", "application/json")
  .body("{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"flash-v1\",\n  \"config\": {\n    \"speed\": 1\n  }\n}")
  .asString();
```

```php Model flash-v1 (chỉ hỗ trợ speed)
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.omicx.one/tts', [
  'body' => '{
  "text": "Xin chào, đây là bản demo từ OMICX",
  "voiceId": "EGvMuAim33",
  "modelId": "flash-v1",
  "config": {
    "speed": 1
  }
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-Api-Key' => 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  ],
]);

echo $response->getBody();
```

```csharp Model flash-v1 (chỉ hỗ trợ speed)
using RestSharp;

var client = new RestClient("https://api.omicx.one/tts");
var request = new RestRequest(Method.POST);
request.AddHeader("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"flash-v1\",\n  \"config\": {\n    \"speed\": 1\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Model flash-v1 (chỉ hỗ trợ speed)
import Foundation

let headers = [
  "X-Api-Key": "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "Content-Type": "application/json"
]
let parameters = [
  "text": "Xin chào, đây là bản demo từ OMICX",
  "voiceId": "EGvMuAim33",
  "modelId": "flash-v1",
  "config": ["speed": 1]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.omicx.one/tts")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

### Model ultra-v1 (đầy đủ config mặc định)

**Request**

```json
{
  "text": "Xin chào, đây là bản demo từ OMICX",
  "voiceId": "EGvMuAim33",
  "modelId": "ultra-v1",
  "config": {
    "age": "adult",
    "speechEmotion": "neutral",
    "speechStyle": "normal",
    "speed": 1
  }
}
```

**Response**

```json
{
  "trackingId": "018f8b3c-6d1b-7a2c-8e4f-5b6c7d8e9f0a",
  "audioUrl": "https://api.omicx.one/tts/audio?k=MDE5ZjY4ZmE...",
  "audioDuration": 3.4,
  "fileSizeBytes": 68432,
  "processingTimeMs": 512,
  "languageCode": "vi"
}
```

**SDK Code**

```python Model ultra-v1 (đầy đủ config mặc định)
import requests

url = "https://api.omicx.one/tts"

payload = {
    "text": "Xin chào, đây là bản demo từ OMICX",
    "voiceId": "EGvMuAim33",
    "modelId": "ultra-v1",
    "config": {
        "age": "adult",
        "speechEmotion": "neutral",
        "speechStyle": "normal",
        "speed": 1
    }
}
headers = {
    "X-Api-Key": "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript Model ultra-v1 (đầy đủ config mặc định)
const url = 'https://api.omicx.one/tts';
const options = {
  method: 'POST',
  headers: {
    'X-Api-Key': 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
    'Content-Type': 'application/json'
  },
  body: '{"text":"Xin chào, đây là bản demo từ OMICX","voiceId":"EGvMuAim33","modelId":"ultra-v1","config":{"age":"adult","speechEmotion":"neutral","speechStyle":"normal","speed":1}}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go Model ultra-v1 (đầy đủ config mặc định)
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://api.omicx.one/tts"

	payload := strings.NewReader("{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"ultra-v1\",\n  \"config\": {\n    \"age\": \"adult\",\n    \"speechEmotion\": \"neutral\",\n    \"speechStyle\": \"normal\",\n    \"speed\": 1\n  }\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby Model ultra-v1 (đầy đủ config mặc định)
require 'uri'
require 'net/http'

url = URI("https://api.omicx.one/tts")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["X-Api-Key"] = 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"ultra-v1\",\n  \"config\": {\n    \"age\": \"adult\",\n    \"speechEmotion\": \"neutral\",\n    \"speechStyle\": \"normal\",\n    \"speed\": 1\n  }\n}"

response = http.request(request)
puts response.read_body
```

```java Model ultra-v1 (đầy đủ config mặc định)
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://api.omicx.one/tts")
  .header("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
  .header("Content-Type", "application/json")
  .body("{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"ultra-v1\",\n  \"config\": {\n    \"age\": \"adult\",\n    \"speechEmotion\": \"neutral\",\n    \"speechStyle\": \"normal\",\n    \"speed\": 1\n  }\n}")
  .asString();
```

```php Model ultra-v1 (đầy đủ config mặc định)
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://api.omicx.one/tts', [
  'body' => '{
  "text": "Xin chào, đây là bản demo từ OMICX",
  "voiceId": "EGvMuAim33",
  "modelId": "ultra-v1",
  "config": {
    "age": "adult",
    "speechEmotion": "neutral",
    "speechStyle": "normal",
    "speed": 1
  }
}',
  'headers' => [
    'Content-Type' => 'application/json',
    'X-Api-Key' => 'omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
  ],
]);

echo $response->getBody();
```

```csharp Model ultra-v1 (đầy đủ config mặc định)
using RestSharp;

var client = new RestClient("https://api.omicx.one/tts");
var request = new RestRequest(Method.POST);
request.AddHeader("X-Api-Key", "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"text\": \"Xin chào, đây là bản demo từ OMICX\",\n  \"voiceId\": \"EGvMuAim33\",\n  \"modelId\": \"ultra-v1\",\n  \"config\": {\n    \"age\": \"adult\",\n    \"speechEmotion\": \"neutral\",\n    \"speechStyle\": \"normal\",\n    \"speed\": 1\n  }\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift Model ultra-v1 (đầy đủ config mặc định)
import Foundation

let headers = [
  "X-Api-Key": "omx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "Content-Type": "application/json"
]
let parameters = [
  "text": "Xin chào, đây là bản demo từ OMICX",
  "voiceId": "EGvMuAim33",
  "modelId": "ultra-v1",
  "config": [
    "age": "adult",
    "speechEmotion": "neutral",
    "speechStyle": "normal",
    "speed": 1
  ]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://api.omicx.one/tts")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```