Документация

Синтез речи, транскрипция и анализ аудио через единый REST API. Ключ — в заголовке, результат — бинарный аудиофайл или JSON.

Открыть Swagger (OpenAPI)

Быстрый старт

  1. Зарегистрируйтесь и получите API-ключ вида rtt_… в кабинете.
  2. Передавайте ключ в заголовке X-Api-Key каждого запроса.
  3. Базовый URL — https://ttsapi.ru.
curl -X POST https://ttsapi.ru/v1/synthesize \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: rtt_…" \
  -d '{"text":"Привет, мир!","voice":"preset_anna","format":"mp3"}' \
  --output hello.mp3

Аутентификация

Все эндпоинты /v1/* (кроме каталога голосов) требуют API-ключ в заголовке X-Api-Key.

X-Api-Key: rtt_…

Также поддерживаются Authorization: Bearer rtt_… и X-RapidAPI-Key для интеграции через RapidAPI.

Синтез речи

POST /v1/synthesize принимает JSON и возвращает бинарный аудиофайл (mp3, wav или ogg).

ПолеТипОписание
textstringТекст для озвучивания (до 5000 символов)
voicestringID голоса, например preset_anna
formatstringmp3 (по умолчанию), wav, ogg
sample_rateintЧастота дискретизации, например 24000
speedfloatСкорость речи (по умолчанию 1.0)
languagestringЯзык синтеза (по умолчанию — язык голоса): ru, en, zh, ja, ko, de, es, fr, it Если не указан, берётся язык голоса.
normalizeboolЧисла прописью (по умолчанию true)

cURL

curl -X POST https://ttsapi.ru/v1/synthesize \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: rtt_…" \
  -d '{"text":"Добрый день!","voice":"preset_anna","format":"mp3"}' \
  --output speech.mp3

Python

import httpx

response = httpx.post(
    "https://ttsapi.ru/v1/synthesize",
    headers={"X-Api-Key": "rtt_…"},
    json={
        "text": "Добрый день!",
        "voice": "preset_anna",
        "format": "mp3",
    },
    timeout=60.0,
)
response.raise_for_status()
with open("speech.mp3", "wb") as f:
    f.write(response.content)

JavaScript

const response = await fetch("https://ttsapi.ru/v1/synthesize", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": "rtt_…",
  },
  body: JSON.stringify({ text: "Добрый день!", voice: "preset_anna", format: "mp3" }),
});

if (!response.ok) throw new Error(await response.text());
const blob = await response.blob();
// Браузер: URL.createObjectURL(blob) → воспроизведение в теге audio
// Node.js: fs.writeFileSync("speech.mp3", Buffer.from(await blob.arrayBuffer()))

C# (.NET)

using var client = new HttpClient();
using var request = new HttpRequestMessage(HttpMethod.Post, "https://ttsapi.ru/v1/synthesize");
request.Headers.Add("X-Api-Key", "rtt_…");
request.Content = new StringContent(
    """{"text":"Добрый день!","voice":"preset_anna","format":"mp3"}""",
    System.Text.Encoding.UTF8, "application/json");

using var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
await File.WriteAllBytesAsync("speech.mp3", await response.Content.ReadAsByteArrayAsync());

Стриминг чанками

POST /v1/synthesize/stream отдаёт аудио чанками по мере генерации — воспроизведение начинается до окончания синтеза длинного текста. Доступно на тарифах Pro и Business; Free и Basic получают 403 streaming_forbidden.

Тело запроса совпадает с POST /v1/synthesize. Ответ — поток audio/mpeg без заголовка Content-Length: каждый чанк пишется в тело сразу после синтеза.

cURL

curl -X POST https://ttsapi.ru/v1/synthesize/stream \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: rtt_…" \
  -d '{"text":"Первое предложение. Второе предложение. Третье предложение.","voice":"preset_anna","format":"mp3"}' \
  --no-buffer \
  --output speech_stream.mp3

Python

import httpx

with httpx.stream(
    "POST",
    "https://ttsapi.ru/v1/synthesize/stream",
    headers={"X-Api-Key": "rtt_…"},
    json={"text": "Первое предложение. Второе предложение.", "voice": "preset_anna", "format": "mp3"},
    timeout=60.0,
) as response:
    response.raise_for_status()
    with open("speech_stream.mp3", "wb") as f:
        for chunk in response.iter_bytes():
            f.write(chunk)

MP3 стримится по предложениям (кадры MP3 конкатенируются корректно); WAV/OGG кодируются целиком и режутся на чанки, чтобы поток оставался валидным контейнером.

Синтез длинных текстов

POST /v1/synthesize/async ставит длинный текст (аудиокнига / длинная статья) в очередь как фоновую задачу. Текст разбивается на абзацы, каждый синтезируется отдельно, затем склеивается в один WAV с точным таймкод-манифестом.

Опрашивайте `GET /v1/synthesize/async/{job_id}` для манифеста и скачивайте аудио через `GET /v1/synthesize/async/{job_id}/audio`. Передайте `webhookUrl`, чтобы получить уведомление о завершении.

Синтез длинных текстов возвращает WAV (PCM), чтобы таймкоды абзацев оставались сэмпл-точными.

ПолеТипОписание
textstringТекст для озвучивания (до 5000 символов)
voicestringID голоса, например preset_anna
formatstringwav (по умолчанию),
sample_rateintЧастота дискретизации, например 24000
speedfloatСкорость речи (по умолчанию 1.0)
languagestringЯзык синтеза (по умолчанию — язык голоса):

cURL

curl -X POST "https://ttsapi.ru/v1/synthesize/async" \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: rtt_…" \
  -d '{"text":"Глава первая. Абзац один.\n\nАбзац два.","voice":"preset_anna","format":"wav"}'

# → 202 { "job_id": "…", "status": "queued", "estimated_seconds": 12 }

# Результат
curl "https://ttsapi.ru/v1/synthesize/async/{job_id}" \
  -H "X-Api-Key: rtt_…"

# → 200 { "job_id": "…", "status": "completed", "result": { "segments": [ … ], "duration_milliseconds": 18420, … } }

curl "https://ttsapi.ru/v1/synthesize/async/{job_id}/audio" \
  -H "X-Api-Key: rtt_…" \
  --output audiobook.wav

Python

from ttsapi import RussianTtsClient

client = RussianTtsClient(api_key="rtt_…")

job = client.synthesize_async("Глава первая…", voice="preset_anna", format="wav")
result = client.get_synthesis_job(job["job_id"])
while result["status"] not in ("completed", "failed"):
    result = client.get_synthesis_job(job["job_id"])

audio = client.download_synthesis_audio(job["job_id"])
open("audiobook.wav", "wb").write(audio)

Аудиоэффекты

POST /v1/audio/effects применяет цепочку аудиоэффектов к загруженному файлу как фоновую задачу. Поддерживаются: reverb, compressor, eq, distortion, chorus, pitch, timestretch.

Опрашивайте `GET /v1/audio/effects/{job_id}` и скачивайте результат через `GET /v1/audio/effects/{job_id}/audio`. Передайте `webhookUrl`, чтобы получить уведомление.

ПолеТипОписание
audiofileАудиофайл (wav, mp3, ogg, flac до 25 МБ / 15 мин) (wav, mp3, ogg, flac)
effectsstringJSON-строка: массив дескрипторов эффектов
output_formatstringwav (по умолчанию), mp3, ogg
curl -X POST https://ttsapi.ru/v1/audio/effects \
  -H "X-Api-Key: rtt_…" \
  -F "audio=@voice.mp3" \
  -F 'effects=[{"type":"reverb","room_size":0.5},{"type":"pitch","semitones":2}]' \
  -F "output_format=mp3"

# → 202 { "job_id": "…", "status": "queued" }

curl https://ttsapi.ru/v1/audio/effects/{job_id} -H "X-Api-Key: rtt_…"
# → 200 { "status": "completed", "result": { "format": "mp3", "duration_milliseconds": … } }

curl https://ttsapi.ru/v1/audio/effects/{job_id}/audio -H "X-Api-Key: rtt_…" --output result.mp3

Видеоэффекты

POST /v1/video/effects применяет эффекты к видео (mode=mux) или к его аудио-дорожке (mode=audio) как фоновую задачу. В mux можно передать отдельный аудиофайл, который заменит аудио-дорожку.

Опрашивайте `GET /v1/video/effects/{job_id}` и скачивайте результат через `GET /v1/video/effects/{job_id}/file`.

ПолеТипОписание
videofileВидеофайл (mp4, webm, …)
audiofileОпциональный аудиофайл для mode=mux
effectsstringJSON-строка: массив дескрипторов эффектов
modestringmux (по умолчанию), audio
output_formatstringmp4, webm (mux) / wav, mp3, ogg (audio)
curl -X POST https://ttsapi.ru/v1/video/effects \
  -H "X-Api-Key: rtt_…" \
  -F "video=@clip.mp4" \
  -F 'effects=[{"type":"compressor","threshold_db":-18,"ratio":3}]' \
  -F "mode=mux" \
  -F "output_format=mp4"

# → 202 { "job_id": "…", "status": "queued" }

curl https://ttsapi.ru/v1/video/effects/{job_id}/file -H "X-Api-Key: rtt_…" --output result.mp4

Голоса

GET /v1/voices возвращает список голосов без авторизации; GET /v1/voices/{id} — один голос.

Всего 29 preset-голосов (по умолчанию — Анна, `preset_anna`); доступны, например: preset_anna, preset_maksim, preset_pavel, preset_m01, preset_w01

curl https://ttsapi.ru/v1/voices

Клонирование голоса

POST /v1/voices/clone создаёт клонированный голос из 1–3 образцов речи одного диктора. Возвращает `id`, который используется как `voice` вместе с `model=premium`.

Один образец: wav/mp3/ogg/flac/m4a/aac до 10 МБ, чистый голос без шума и музыки, плюс его транскрипт (prompt_text). Premium-движок CosyVoice доступен на тарифах Pro и Business.

curl -X POST https://ttsapi.ru/v1/voices/clone \
  -H "X-Api-Key: rtt_…" \
  -F "name=my_voice" \
  -F "samples=@voice_1.wav" \
  -F "samples=@voice_2.wav" \
  -F "samples=@voice_3.wav"

# → 201 { "id": "clone_…", "name": "my_voice", "language": "ru",
#         "sample_count": 3, "created_at": "…" }

# GET    /v1/voices/clone
# GET    /v1/voices/clone/{id}
# DELETE /v1/voices/clone/{id}   # → 204

Используйте клонированный голос в POST /v1/synthesize и POST /v1/synthesize/stream:

curl -X POST https://ttsapi.ru/v1/synthesize \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: rtt_…" \
  -d '{"text":"Привет!","voice":"clone_…","model":"premium","format":"mp3"}'

Транскрипция

Асинхронный POST /v1/transcribe принимает multipart/form-data и сразу возвращает job_id. Результат забирается опросом GET /v1/transcribe/{job_id}.

ПолеТипОписание
audiofileАудиофайл (wav, mp3, ogg, flac до 25 МБ / 15 мин)
languagestringКод языка ISO 639-1 (например ru, en, de). Необязательный — если не указан, определяется автоматически.
diarizationboolРазделение спикеров (требует тариф с диаризацией)
keytermsstringСписок терминов через запятую для точного распознавания (keyterm prompting)
webhookUrlstringURL для уведомления о готовности

Поддерживаются коды языков (ISO 639-1): ru, en, de, es, fr, uk, kk, uz, zh и другие — всего модель Whisper поддерживает ~99 языков.

# Запуск задачи
curl -X POST https://ttsapi.ru/v1/transcribe \
  -H "X-Api-Key: rtt_…" \
  -F "audio=@meeting.mp3" \
  -F "language=ru" \
  -F "diarization=true"

# → 202 { "job_id": "…", "status": "queued" }

# Результат
curl https://ttsapi.ru/v1/transcribe/{job_id} \
  -H "X-Api-Key: rtt_…"

Для коротких файлов (до 3 минут) есть синхронный вариант — POST /v1/transcribe/sync, возвращающий результат сразу.

Можно передать поле `keyterms` — список терминов через запятую: модель будет распознавать их точнее (keyterm prompting). Ответ `segments` теперь содержит по-словные таймкоды `words` (`word`, `start`, `end`, `confidence`).

Субтитры

GET /v1/transcribe/{job_id}/subtitles выгружает готовую транскрипцию как субтитры WebVTT или SubRip.

Параметр `format` — `vtt` (по умолчанию) или `srt`.

Если задача ещё не завершена, вернётся `409 subtitles_unavailable`.

curl -OJ https://ttsapi.ru/v1/transcribe/{job_id}/subtitles?format=srt \
  -H "X-Api-Key: rtt_…"

Анализ аудио

POST /v1/analyze возвращает транскрипцию, эмоции по сегментам и ключевые слова.

Параметр language — код языка ISO 639-1 (например ru, en); если не указан, язык определяется автоматически. Поддерживаются коды языков (ISO 639-1).

Поле `keyterms` (через запятую) повышает точность распознавания доменных терминов.

curl -X POST https://ttsapi.ru/v1/analyze \
  -H "X-Api-Key: rtt_…" \
  -F "audio=@call.mp3" \
  -F "emotions=true" \
  -F "keywords=true"

# → { "transcript": "…", "segments": […], "keywords": […] }

Тематики

POST /v1/analyze/topics классифицирует текст по темам без загрузки аудио: возвращает список тем с релевантностью (0..1).

curl -X POST https://ttsapi.ru/v1/analyze/topics \
  -H "X-Api-Key: rtt_…" \
  -H "Content-Type: application/json" \
  -d '{"text": "Запустили стартап и вывели продукт на рынок."}'

# → { "topics": [{"topic": "business", "score": 0.09}] }

Резюмирование

POST /v1/analyze/summarize делает экстрактивное резюме текста без загрузки аудио. Параметр `max_sentences` (1..10, по умолчанию 3) задаёт число предложений.

curl -X POST https://ttsapi.ru/v1/analyze/summarize \
  -H "X-Api-Key: rtt_…" \
  -H "Content-Type: application/json" \
  -d '{"text": "Первое предложение. Второе. Третье. Четвёртое.", "max_sentences": 2}'

# → { "summary": "…", "sentences": […] }

Определение языка

POST /v1/detect-language определяет язык текста без загрузки аудио: возвращает код языка ISO 639-1 и уверенность (0..1).

Полезен перед выбором голоса или принудительным указанием языка транскрипции.

curl -X POST https://ttsapi.ru/v1/detect-language \
  -H "X-Api-Key: rtt_…" \
  -H "Content-Type: application/json" \
  -d '{"text": "Привет! Как дела?"}'

# → { "language": "ru", "confidence": 0.99 }

Редактирование PII

POST /v1/redact заменяет персональные данные в тексте на метки типа и возвращает маскированный текст со списком найденных сущностей и их позициями. Загрузка аудио не требуется.

Маскируются имена, организации, локации, даты и суммы (NER), а также телефоны, email и номера карт (регулярные выражения).

curl -X POST https://ttsapi.ru/v1/redact \
  -H "X-Api-Key: rtt_…" \
  -H "Content-Type: application/json" \
  -d '{"text": "Иван позвонил на +7 900 123-45-67 из Москвы."}'

# → { "redacted_text": "[PER] позвонил на [PHONE] из [LOC].", "entities": […], "count": 3 }

Модерация

POST /v1/moderate проверяет текст на ненормативную лексику, оскорбления и язык вражды без загрузки аудио: возвращает флаг, общий балл (0..1) и найденные термины с категориями.

Категории: profanity, insult, hate. Лёгкий лексиконный классификатор — быстрый первый фильтр, а не полноценная модель токсичности.

curl -X POST https://ttsapi.ru/v1/moderate \
  -H "X-Api-Key: rtt_…" \
  -H "Content-Type: application/json" \
  -d '{"text": "Это оскорбительное сообщение.", "language": "ru"}'

# → { "flagged": true, "score": 0.5, "categories": ["insult"], "matches": […] }

Стриминговая транскрипция

WS /v1/transcribe/stream выполняет потоковую транскрипцию по WebSocket (тарифы Pro/Business). Отправляйте сырые PCM16-кадры (little-endian, mono, 16 кГц) бинарными сообщениями; сервер отвечает JSON-событиями: `session`, `vad`, `partial` и `final`.

Тарифы Free и Basic получают `403 streaming_forbidden`.

Аутентификация: ключ в query-строке `?api_key=…` или заголовке `X-Api-Key` (браузеры не задают заголовки при WS-хендшейке).

Клиент → сервер: бинарные PCM16-кадры (little-endian, mono, 16 кГц) и текстовый кадр `{"type":"stop"}` для финализации.

Сервер → клиент — JSON-события:

ТипСобытиеОписание
sessionstarted / endedЖизненный цикл сессии (+`session_id`, `audio_seconds`).
vadspeech_started / speech_endedДетекция речи: начало и конец фразы.
partialПромежуточный транскрипт во время речи.
finalФинальный транскрипт завершённой фразы.
errorОшибка сессии (`quota_exceeded`, `stream_failed`).

Параметры запроса: `language`, `keyterms` (через запятую), `interim=true|false`.

Квота списывается по переданному аудио (1 сек = 32 000 байт PCM16).

JavaScript

const ws = new WebSocket("wss://ttsapi.ru/v1/transcribe/stream?api_key=rtt_…&language=ru");

ws.binaryType = "arraybuffer";
ws.onmessage = (event) => console.log(JSON.parse(event.data));

ws.send(pcm16Bytes);
ws.send(JSON.stringify({ type: "stop" }));

Python

import asyncio, json, websockets

async def main():
    async with websockets.connect(
        "wss://ttsapi.ru/v1/transcribe/stream?api_key=rtt_…"
    ) as ws:
        await ws.send(open("speech.raw", "rb").read())
        await ws.send(json.dumps({"type": "stop"}))
        async for message in ws:
            print(json.loads(message))

asyncio.run(main())

VAD / turn detection

POST /v1/vad находит сегменты речи (Silero VAD) в загруженном аудио и возвращает их границы. WebSocket-вариант в реальном времени шлёт события `speech_started` / `speech_ended` — база для голосовых агентов.

curl -X POST https://ttsapi.ru/v1/vad \
  -H "X-Api-Key: rtt_…" \
  -F "audio=@meeting.mp3"

# → { "segments": [{"start": 0.1, "end": 2.4}, {"start": 3.0, "end": 5.2}],
#     "speech_ratio": 0.68, "duration_seconds": 5.2, "processing_time_ms": 12 }

WS /v1/vad/stream— стриминговый turn detection: только VAD-события, без распознавания.

const ws = new WebSocket("wss://ttsapi.ru/v1/vad/stream?api_key=rtt_…");
ws.binaryType = "arraybuffer";
ws.onmessage = (event) => console.log(JSON.parse(event.data));

// ← {"type":"vad","event":"speech_started","start":1.20}
// ← {"type":"vad","event":"speech_ended","start":1.20,"end":4.85}

Приведение аудио к PCM16: `ffmpeg -i in.mp3 -ar 16000 -ac 1 -f s16le out.raw`.

Batch

POST /v1/batch/synthesize и POST /v1/batch/analyze запускают пакетную обработку: до 20 задач синтеза или до 10 задач анализа (аудио inline base64). Возвращают `202` с `batch_id`.

Результат забирается опросом: GET /v1/batch/{batch_id}.

# Пакетный синтез
curl -X POST https://ttsapi.ru/v1/batch/synthesize \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: rtt_…" \
  -d '{"items":[{"text":"Первый текст","voice":"preset_anna"},{"text":"Второй текст","voice":"preset_m01"}]}'

# → 202 { "batch_id": "…", "status": "queued", "item_count": 2 }

# Пакетный анализ
curl -X POST https://ttsapi.ru/v1/batch/analyze \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: rtt_…" \
  -d '{"items":[{"audio":"BASE64…","language":"ru"}]}'

# Результат
curl https://ttsapi.ru/v1/batch/{batch_id} \
  -H "X-Api-Key: rtt_…"

Квоты и лимиты

GET /v1/usage показывает остаток квоты по текущему тарифу: символы синтеза, минуты транскрипции и запросы анализа.

curl https://ttsapi.ru/v1/usage \
  -H "X-Api-Key: rtt_…"

Ошибки

Ошибки возвращаются в формате RFC 7807 (Problem Details) с дополнительным полем code.

КодHTTPОписание
text_too_long413Текст превышает лимит
text_invalid_characters400Текст содержит символы, которые не поддерживает выбранный голос
quota_exceeded429Лимит тарифа исчерпан
streaming_forbidden403Стриминг недоступен на текущем тарифе
audio_invalid400Некорректный аудиофайл
audio_too_large413Аудиофайл превышает допустимый размер
job_not_found404Задача не найдена
engine_unavailable503Инференс временно недоступен
premium_voice_forbidden403Premium-движок недоступен на текущем тарифе
clone_forbidden403Клонирование недоступно на текущем тарифе
diarization_forbidden403Диаризация недоступна на текущем тарифе
subtitles_unavailable409Субтитры недоступны: задача ещё не завершена
audio_too_long413Аудио превышает допустимую длительность

Python SDK

Официальная Python-обёртка: синтез, стриминг, транскрипция, анализ, текст-интеллект и batch.

Установка

pip install ttsapi-client

Быстрый старт

from ttsapi import RussianTtsClient

client = RussianTtsClient(api_key="rtt_…")

audio = client.synthesize("Привет! Это синтез русской речи.", voice="preset_anna", format="mp3")
open("speech.mp3", "wb").write(audio)

for chunk in client.synthesize_stream("Первое предложение. Второе."):
    pass

job = client.transcribe("audio.wav", keyterms=["диагноз"])
result = client.get_transcription_job(job["job_id"])
while result["status"] not in ("completed", "failed"):
    result = client.get_transcription_job(job["job_id"])

transcript = client.transcribe_sync("audio.wav")
analysis = client.analyze_sync("audio.wav")
lang = client.detect_language("Как дела?")
topics = client.topics("Нейросети и алгоритмы")
summary = client.summarize("Длинный текст.", max_sentences=3)
redacted = client.redact("Иван позвонил на +7 900 123-45-67 из Москвы.")

batch = client.batch_synthesize([{"text": "Первый текст", "voice": "preset_anna"}])
status = client.get_batch(batch["batch_id"])

Параметры: `api_key` (обязателен), `base_url` (по умолчанию `https://ttsapi.ru`), `timeout` (120.0 с). Ошибки — `RussianTtsError` с полями `.status`, `.code`, `.message`.

TypeScript SDK

Официальная TypeScript/JavaScript-обёртка. Ноль зависимостей, Node.js 18+.

Установка

npm install ttsapi-client

Быстрый старт

import { RussianTtsClient } from "ttsapi-client";
import { writeFile } from "node:fs/promises";

const client = new RussianTtsClient({ apiKey: "rtt_…" });

const audio = await client.synthesize("Привет! Это синтез русской речи.", {
  voice: "preset_anna",
  format: "mp3",
});
await writeFile("speech.mp3", audio);

for await (const chunk of client.synthesizeStream("Первое предложение. Второе.")) {
  // …
}

const job = await client.transcribe("audio.wav", { keyterms: ["диагноз"] });
let result = await client.getTranscriptionJob(job.job_id);
while (!["completed", "failed"].includes(result.status)) {
  await new Promise((r) => setTimeout(r, 1000));
  result = await client.getTranscriptionJob(job.job_id);
}

const transcript = await client.transcribeSync("audio.wav");
const analysis = await client.analyzeSync("audio.wav");
const lang = await client.detectLanguage("Как дела?");
const topics = await client.topics("Нейросети и алгоритмы");
const summary = await client.summarize("Длинный текст.", undefined, 3);
const redacted = await client.redact("Иван позвонил на +7 900 123-45-67 из Москвы.");

const batch = await client.batchSynthesize([{ text: "Первый текст", voice: "preset_anna" }]);
const status = await client.getBatch(batch.batch_id);

Параметры: `apiKey` (обязателен), `baseUrl` (по умолчанию `https://ttsapi.ru`), `timeoutMs` (120000). Ошибки — `RussianTtsError` с полями `.status`, `.code`, `.message`.

WebSocket-эндпоинты (стриминговая транскрипция, VAD) подключаются напрямую WS-клиентом — см. разделы выше.