Перейти до вмісту
tonvio

API озвучення тексту

API озвучення тексту: увесь контракт — до реєстрації

У tonvio є публічний HTTP API для синтезу мовлення та клонування голосу. Ця сторінка — повний довідник: ендпоінти, поля запиту, ліміти, коди помилок і машинна специфікація OpenAPI 3.1. Нічого не сховано за логіном, тож інженер може оцінити інтеграцію раніше, ніж хтось заведе обліковий запис.

API працює на тому самому рушії, що й кабінет: ті самі голоси та можливості генерації, та сама черга, той самий готовий MP3.

Базова адреса

Усі шляхи нижче — відносно цієї адреси. API говорить лише на JSON; виняток один — multipart-ендпоінт для завантаження зразка голосу.

https://api.tonvio.net/api/v1

Автентифікація

Передайте ключ як Bearer-токен у заголовку Authorization або в заголовку X-API-Key — це рівнозначно. Ключ — серверний секрет: хто ним володіє, той витрачає ваші кредити, тому у фронтенд його класти не можна. Ключі створюються в кабінеті й показуються повністю рівно один раз.

Authorization: Bearer tvk_your_key_here
# or
X-API-Key: tvk_your_key_here

Як влаштована інтеграція

API асинхронний за задумом. Синтез довгого тексту триває хвилини, а HTTP-запит, що висить хвилинами, помирає десь посередині — у проксі, балансувальнику або CDN. Тому сервер приймає завдання, відповідає одразу, а клієнт опитує.

  1. 01

    Створіть завдання

    POST /speech з текстом та id голосу. Відповідь — 202 з id завдання і статусом queued. Кредити цієї миті резервуються, а не списуються.

  2. 02

    Опитуйте статус

    GET /speech/{id} кожні 2–3 секунди. progress сягає 100 лише разом зі статусом completed — доки завдання триває, стеля 99, тож «100%» ніколи не означає «майже готово».

  3. 03

    Заберіть аудіо

    За статусу completed в audio_url лежить посилання на MP3. Посилання короткоживуче (близько шести годин) — запитайте завдання ще раз і отримаєте свіже.

  4. 04

    Обробіть термінальні стани

    failed і canceled — теж кінець. За відмови резерв повертається, а error_code каже, чи є сенс повторювати. Повтор — це ЗАВЖДИ нове завдання і нове списання.

# 1. Create a job
curl -X POST https://api.tonvio.net/api/v1/speech \
  -H "Authorization: Bearer tvk_your_key_here" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: replace-with-a-unique-request-id" \
  -d '{ "text": "Hello from tonvio!", "voice_id": "el_XXXX", "language": "en" }'
# → 202 { "id": "JOB_ID", "status": "queued", "characters": 18, "queue_position": 1 }

# 2. Poll until completed (every 2-3 seconds)
curl https://api.tonvio.net/api/v1/speech/JOB_ID \
  -H "Authorization: Bearer tvk_your_key_here"
# → { "status": "completed", "progress": 100, "audio_url": "https://cdn.tonvio.net/..." }

# 3. Or read what this key may actually spend and run into
curl https://api.tonvio.net/api/v1/account \
  -H "X-API-Key: tvk_your_key_here"

Ендпоінти

Чотирнадцять ендпоінтів і один конверт. Будь-який запит потребує ключа, а в кожного ключа є набір прав з останньої колонки.

МетодШляхЩо робитьПраво
POST/speechСтворити завдання синтезу (асинхронно).speech
GET/speech/{id}Статус завдання і, коли готово, посилання на аудіо.speech:read
GET/speechЗавдання цього ключа, свіжі першими, курсорна пагінація.speech:read
POST/speech/{id}/cancelЗупинити завдання; за відрендерене списується, залишок повертається.speech
DELETE/speech/{id}Видалити завдання та його аудіо; незавершене спершу зупиняє.speech
GET/voicesКаталог голосів, якими цей ключ може озвучувати.voices
GET/voices/{id}Один голос за id.voices
GET/voices/{id}/warmЧи готовий голос до синтезу.voices
POST/voices/{id}/warmПрогріти голос до першого платного завдання.voices
GET/accountБаланс, чинні ліміти та витрати цього ключа.account
POST/voice-clonesЗамовити клон голосу (асинхронно).clone
GET/voice-clones/{id}Стан заявки і, коли готово, її voice_id.clone
GET/voice-clonesЗаявки цього ключа, курсорна пагінація.clone
DELETE/voice-clones/{id}Зняти заявку або видалити клон і звільнити слот у провайдера.clone

Права ключа

У кожного ключа свій набір прав. Заводський набір — speech, voices, account: він відкриває все, що API вмів і раніше. Право clone видається окремо. Звернення до ендпоінта без права — 403 insufficient_scope, а в полі required перелічено права, будь-якого з яких вистачило б. Ключу можна призначити й термін: після нього будь-який запит отримує 401 api_key_expired. Свої права й термін ключ читає в GET /account.

ПравоЩо відкриває
speechСтворювати й скасовувати завдання. Покриває і speech:read.
speech:readЛише читати стан завдань — право для спостерігача, якому не можна витрачати гроші.
voicesЧитати каталог голосів.
accountЧитати баланс, ліміти та витрати.
cloneЗамовляти й видаляти клони голосу. До заводського набору НЕ входить.

POST /speech — тіло запиту

Ідентифікатор голосу потрібен один: або каталожний voice_id, або ідентифікатор того самого голосу в зовнішньому каталозі, на якому побудований перший провайдер.

ПолеЗначення
textобов'язковоТекст для озвучення. Тариф обмежує символи на запит — чинна цифра в GET /account (limits.max_chars_per_request).
voice_idодне з двохКаталожний id голосу з GET /voices або voice_id готового приватного клона.
elevenlabs_voice_idодне з двохІдентифікатор голосу в зовнішньому каталозі, на якому побудований перший провайдер. Провайдери, що з ним не працюють, його відхиляють.
voice_engineнеобов'язковоРушій синтезу. У каталожного голосу береться його власний дефолт; у приватного клона дефолту немає — передайте явно. Провайдери без поняття «рушій» поле ігнорують.
modelнеобов'язковоПсевдонім voice_engine. Якщо надіслані обидва, вони мають збігатися.
languageнеобов'язковоМова синтезу, BCP 47 (uk, en, pt-BR). Там, де голос — це стек клонів за мовами, мовчання не означає «хай вирішить рушій»: це мовчазний вибір. Мови, якими голос справді володіє, — у його полі languages.
settingsнеобов'язковоТонке налаштування: stability (0–1), settings_preset, delay_between_chunks (0–60 с). Незнайомий ключ відхиляється, а не ігнорується мовчки.
idempotency_keyнеобов'язковоТе саме, що заголовок Idempotency-Key. Якщо надіслані обидва, вони мають збігатися.

Що повертається

202 з id завдання, його статусом, зарезервованими символами та позицією в черзі. Якщо в тексті була розмітка, якої цільовий провайдер не розуміє, у відповіді з'явиться warnings: кожен замінений або знятий тег із лічильником. За знятий тег гроші не беруться — це єдине місце, де сервер змінює ваш текст, і він завжди про це каже.

Кредити, частота та обсягові квоти

API працює на куплених символьних кредитах: 1 символ = 1 кредит. Підписки й бонуси за нього не платять, а читальні запити баланс не витрачають узагалі. Скільки реально доступно — у GET /account (credits.api_spendable_chars); за нуля /speech відповідає 402 insufficient_balance.

  • Частота: типово 300 запитів на хвилину на ключ. Ключу можна призначити свою цифру, а чинна приїздить у заголовках відповіді RateLimit-Limit, RateLimit-Remaining, RateLimit-Reset і RateLimit-Policy. Ключ накопичує запас: короткий сплеск проходить, рівний перебір — 429 rate_limited.
  • Паралельність: скільки завдань іде водночас, вирішують тариф і ліміти ключа. Типово це ТІ САМІ слоти, що й у кабінету, — вони спільні. Слотів не лишилося — 429 too_many_jobs, а поле scope каже, чия стеля спрацювала: account (спільна з кабінетом) чи key (власна стеля ключа).
  • Обсяг: ключу можна призначити добовий і місячний кап символів. Обидва рахуються в UTC — добовий обнуляється о 00:00 UTC, місячний першого числа. Перевищення — 429 quota_exceeded з полями period, used, limit і resets_at; залишок лежить в usage.key.
  • Усі чинні цифри GET /account віддає разом із limit_sources — картою, де сказано, звідки кожна взялася: key (призначена на ключі), plan (успадкована від тарифу власника) або default (службове значення сервісу, якого немає ні там, ні там).

Ідемпотентність

Передайте idempotency_key у тілі або заголовок Idempotency-Key — і повтор стане безпечним: той самий ключ з тими самими параметрами поверне вихідне завдання, а не створить (і не оплатить) друге. Той самий ключ з іншими параметрами — 409 idempotency_mismatch; ключ, чий результат уже видалено, — 409 idempotency_key_consumed. Без ключа кожен виклик створює нове завдання. У замовленні клона заголовок обов'язковий, і причина груба: повтор замовлення коштує слота в провайдера, а ретраєм слот не повертається.

Клонування голосу через API

Клон замовляється асинхронно, як і озвучення: POST /voice-clones відповідає 202 з нашим id заявки, а клієнт опитує GET /voice-clones/{id} не частіше, ніж сказано в poll_after_seconds. Складання голосу триває хвилини, а не секунди. Щойно status став completed, voice_id — це те, що ви передасте в POST /speech.

  • Два режими. Приватний клон складається з вашого зразка (multipart: mp3, wav, m4a або webm, до 15 МБ; формат перевіряється за РЕАЛЬНИМИ байтами, а не за іменем файлу). Мовний варіант каталожного голосу замовляється в JSON — посилання на файл ми свідомо не приймаємо.
  • Мовний варіант — СПІЛЬНИЙ: складений голос побачать усі користувачі сервісу, видалити його не можна, тому замовлення вимагає явного acknowledge_shared: true. Що ви отримали насправді, завжди сказано в полі visibility — private або shared.
  • consent обов'язковий в обох формах: заява про право на цей голос завдовжки 20–500 символів. Вона зберігається разом із заявкою — поза кабінетом це єдиний слід того, хто заявив право. Клонуйте лише свій голос або голос, на який маєте письмовий дозвіл.
  • Не кожен провайдер уміє кожен вид клона. Там, де поняття немає, відповідь — 501 clone_not_supported_for_provider, причому ДО завантаження файлу: нічого не надіслано і нічого не зарезервовано.
  • Приватного клона немає в публічному каталозі, і рушія за замовчуванням у нього теж немає: під час синтезу ним передавайте voice_engine явно.
  • DELETE /voice-clones/{id} звільняє слот у провайдера й ідемпотентний (204, без тіла). Доки провайдер тримає заявку, прийде 409 clone_in_progress; спільний мовний варіант не видаляється зовсім.
# Order a private clone from your own sample.
# The text fields MUST come before the file, or they never reach the server.
curl -X POST https://api.tonvio.net/api/v1/voice-clones \
  -H "Authorization: Bearer tvk_your_key_here" \
  -H "Idempotency-Key: another-unique-request-id" \
  -F "name=Narrator" \
  -F "consent=I confirm this is my own voice and I may clone it." \
  -F "languages=en,de" \
  -F "[email protected]"
# → 202 { "id": "CLONE_ID", "status": "queued", "visibility": "private",
#         "percent": 0, "poll_after_seconds": 15 }

# Poll until completed, then synthesize with the resulting voice_id.
# A private clone has no default engine, so pass voice_engine explicitly.
curl -X POST https://api.tonvio.net/api/v1/speech \
  -H "Authorization: Bearer tvk_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "text": "Hello!", "voice_id": "VOICE_ID", "voice_engine": "ENGINE_ID" }'

Помилки

У будь-якої відмови один конверт: машинний код error плюс поля, які несе саме цей код, і чесний HTTP-статус. Розгалужуйтеся за кодом, а не за формулюванням message. Заголовок відповіді X-Request-Id зберігайте для підтримки. Повний перелік кодів по кожному ендпоінту — у специфікації OpenAPI; нижче ті, що трапляються найчастіше.

КодЩо означає
invalid_requestТіло запиту невалідне — дивіться message.
missing_api_keyКлюч не передано.
invalid_api_keyКлюч невідомий або відкликаний.
api_key_expiredУ ключа минув термін.
api_key_frozenЗ ключа знято всі права. Оборотно — зверніться до власника сервісу.
insufficient_scopeУ ключа немає права на цей ендпоінт; у required перелічено, чого вистачило б.
insufficient_balanceБракує куплених символів — need каже, скільки коштує запит.
rate_limitedНадто часто для цього ключа. Зачекайте retry_after секунд.
too_many_jobsВільних слотів немає; scope каже, чия стеля спрацювала — account чи key.
quota_exceededДобовий або місячний обсяг ключа вичерпано — див. period, used, limit і resets_at.
voice_not_allowedЦим ключем такий голос використовувати не можна.
voice_warmingГолос прогрівається — повторіть трохи згодом.
voice_language_not_availableГолос не говорить запитаною мовою; в available перелічено ті, якими говорить.
voice_engine_requiredУ голосу немає рушія за замовчуванням — передайте voice_engine явно.
text_too_longТекст довший за ліміт тарифу на один запит; у max сам ліміт.
payload_too_largeТіло запиту більше за межу; у max_bytes сама межа.
idempotency_mismatchЦей ключ ідемпотентності вже використано з іншими параметрами.
generation_unavailableГенерація тимчасово недоступна — повторіть після зазначеної затримки.
internal_errorНесподівана помилка сервера. Повторіть пізніше й передайте підтримці request_id.

Є й друга родина відмов — саме та, з якою інтеграція стикається найчастіше: запит ПРИЙНЯТО (202), а не склалося вже потім. Такі приїздять у error_code в GET /speech/{id} зі статусом failed: queue_timeout, execution_timeout, provider_unavailable, voice_unavailable, synthesis_failed, assembly_failed, output_too_large і generation_failed на все інше. Зарезервовані кредити повертаються в кожному з цих випадків, а error_message — англійська фраза, яку можна показати людині.

Машинна специфікація

Увесь контракт опубліковано одним документом OpenAPI 3.1: кожен ендпоінт, параметр, форма відповіді, код помилки та обидві схеми автентифікації. Довідник вище написано з того самого джерела.

  • Згенеруйте клієнт своєю мовою замість ручних HTTP-викликів.
  • Імпортуйте в HTTP-клієнт — усі запити будуть заповнені наперед.
  • Віддайте нейромережі: це самодостатній опис сервісу.

Відкрити openapi.json

Перевіряється за мета-схемою OpenAPI 3.1 за кожної зміни.

Специфікація — звичайний JSON: віддайте її генератору клієнта, HTTP-клієнту або нейромережі — і все запрацює.

Що інженери запитують найпершим

Документацію можна читати без облікового запису?

Так — ця сторінка й специфікація OpenAPI відкриті. Обліковий запис потрібен лише щоб завести ключ і витрачати кредити, тож оцінити інтеграцію, згенерувати клієнт і розібрати контракт помилок можна раніше, ніж хтось щось підпише.

API синхронний?

Синтез довгого тексту триває хвилини, а запит, що висить стільки ж, помирає у проксі або CDN, тому POST /speech одразу повертає id завдання. Дізнатися про результат можна трьома способами, від простого до зручного: опитувати GET /speech/{id} не частіше, ніж каже його poll_after_seconds; додати ?wait=60 і тримати запит відкритим до кінця роботи (long polling); або задати ключу адресу вебхука й отримувати події speech.completed і speech.failed. Вебхуки підписані HMAC-SHA256 і повторюються при збої, але це сигнал, а не сховище: посилання в тілі живе недовго, по свіже йдіть до GET /speech/{id}.

Скільки коштує виклик API?

Символи. Один символ тексту — один кредит, і беруться вони лише з куплених пакетів: підписки й бонуси за API не платять. Читальні запити безкоштовні. Кредити резервуються під час приймання завдання і повертаються за відмови чи скасування; ціни — на сторінці тарифів.

Які ліміти за частотою?

Типово 300 запитів на хвилину на ключ, із запасом, що гасить короткі сплески; ключу можна призначити свою цифру. Скільки завдань іде водночас, вирішують тариф і ліміти ключа, а ще в ключа можуть бути добовий і місячний капи символів. Чинні значення — у заголовках RateLimit-* і в GET /account.

Чи можна обмежити окремий ключ?

Так. У ключа є набір прав — наприклад, лише читання статусів для моніторингу, — і йому можна призначити свою частоту, слоти, капи символів, дозволених провайдерів, квоту клонів і термін дії. Ключ, з якого знято всі права, заморожений і відповідає 403, доки права не повернуть.

Як зробити повтори безпечними?

Надсилайте Idempotency-Key. Той самий ключ з тими самими параметрами поверне вихідне завдання, а не створить друге, — і мережевий таймаут не перетвориться на подвійне списання. У замовленні клона заголовок обов'язковий: повтор замовлення коштує слота в провайдера.

Голос можна клонувати через API?

Так, якщо в ключа є право clone. Завантажте зразок, опитуйте заявку до статусу completed і користуйтеся отриманим voice_id як будь-яким іншим голосом. Клонуйте лише свій голос або той, на який маєте письмовий дозвіл: кожне замовлення зберігає вашу заяву про право.

Скільки живе посилання на аудіо?

Близько шести годин. Забирайте файл, коли завдання завершилося; якщо посилання знадобиться пізніше — запитайте завдання ще раз, і видасться свіже. Готове аудіо зберігається і в історії кабінету.

Почніть з одного запиту

Заведіть ключ у кабінеті — перший виклик забере хвилину. Перше озвучення безкоштовне, тож увесь цикл (створити, опитати, завантажити) можна перевірити, нічого не витративши.

Уперше в нас? Почніть з огляду озвучення тексту нейромережею.

API озвучення тексту — REST TTS API з клонуванням голосу | tonvio