Один ключ. Говорить звідусіль.
REST API, сумісний з OpenAI SDK, вебхуки з підписом HMAC і MCP-сервер. Модулі для n8n, Make і Zapier та потік у телефонію — у роботі.
Змініть baseURL — решта коду лишається.
Ендпоінти дзеркалять OpenAI: audio.speech.create працює без змін. Ключ hm_live_…, моделі homin-neo-1, homin-pro-1, homin-live-1. Символи рахуються так, як їх отримає провайдер: літери, пробіли, розділові знаки й кожен знак наголосу U+0301 — і ваш, і доданий словником, а пауза — довжиною тегу <break>. Списане приходить у заголовку x-homin-credits.
# один запит — готовий mp3 curl https://homin.ua/v1/audio/speech \ -H "Authorization: Bearer $HOMIN_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"homin-pro-1","voice":"solomiia", "input":"Стари́й за́мок стоїть над Дніпро́м, а на дверя́х — іржавий замо́к і загу́блені ключі́."}' \ --output hello.mp3
Довідник ендпоінтів
https://homin.ua/v1POST | /audio/speech scope: write текст → mp3 потоком · format: mp3_44100_128 або mp3_22050_32 · рекомендовано до 5 000 символів · наголос U+0301 |
POST | /generations/quote scope: read { voice, input } → { chars, credits, upTo? } — стільки спише синтез; upTo — стеля, якщо модель наголосів додасть свої знаки · сам кошторис нічого не списує |
GET | /audio/file/{id}.mp3 збережений файл · готове посилання — у заголовку x-homin-audio-url, діє добу |
GET | /voices голоси: id, ім’я, модель, мови, семпл · без ключа |
POST | /stress/check { text } → текст із наголосами й омографи з варіантами · без ключа |
GET | /usage scope: read кредити, тариф, витрати за місяць, бюджет ключа |
GET | /usage/daily scope: read витрати по днях · days до 90 |
GET | /generations scope: read історія генерацій · limit до 200, cursor, q, status · /generations/{id} — одна |
DELETE | /generations/{id} scope: delete видаляє генерацію |
GET | /keys scope: keys ключі простору · POST — випуск, PATCH і DELETE /keys/{id} · право keys типово вимкнене |
Коди помилок
POST /audio/speech| HTTP | Код | Що означає |
|---|---|---|
400 | input_required | немає тексту в input |
400 | input | текст довший за 20 000 символів |
400 | rejected | немає тексту для озвучення — наприклад, лише наголоси чи паузи |
400 | voice_required | не вказано voice |
400 | format_unsupported | format не mp3_44100_128 і не mp3_22050_32 |
400 | model_unknown | невідома модель |
400 | model_not_supported | модель не озвучує цей голос |
400 | model_not_allowed | ключ не має доступу до цієї моделі |
400 | quota_exceeded | бракує кредитів або вичерпано бюджет ключа |
401 | key_revoked | ключ недійсний, відкликаний або прострочений |
401 | rejected | у запиті немає ключа |
402 | provider_rejected | провайдер синтезу відхилив запит через ліміт свого тарифу |
402 | margin_floor | жоден провайдер не озвучить цей запит у межах мінімальної маржі платформи — спробуйте інший голос чи модель |
403 | insufficient_scope | ключу бракує права «синтез» |
403 | workspace_suspended | простір призупинено — зверніться в підтримку |
403 | provider_not_allowed | голоси ElevenLabs доступні лише в студії |
404 | rejected | голос не знайдено |
413 | payload_too_large | тіло запиту більше за 128 КБ |
422 | voice_unavailable | голос зараз недоступний у провайдера синтезу |
422 | text_too_long | текст задовгий для моделі синтезу |
429 | rate_limited | з однієї адреси понад 600 запитів за хвилину чи 4 синтези одночасно — повторіть після Retry-After |
429 | provider_busy | провайдер синтезу перевантажений — повторіть за хвилину |
502 | provider_auth | провайдер синтезу не прийняв ключ платформи |
502 | provider_rejected | провайдер синтезу відхилив запит |
502 | upstream_failed | синтез не вдався — повторіть запит |
503 | provider_unavailable | немає провайдера, який зараз озвучить цей голос |
503 | provider_quota | у провайдера синтезу вичерпано ліміт платформи |
504 | control_timeout | шлюз не дочекався відповіді сервера HOMIN — повторіть запит |
Ліміти та гарантії
| Free | Pro | Business | Enterprise | |
|---|---|---|---|---|
| Запитів / хв на ключ | — | 120 | 600 | за договором |
| Символів / добу | — | 500 000 | 5 000 000 | без ліміту |
| Паралельних потоків Live | 1 (демо) | — | 50 | 500+ |
| Відповідь API (p95) | — | < 150 мс | < 150 мс | < 100 мс |
| SLA | — | — | 99,9 % | 99,95 % |
Один рядок у конфігу — і асистент говорить українською.
ChatGPT, Claude, Claude Code, Cursor — будь-який клієнт MCP підключається за адресою і сам викликає інструменти HOMIN.
# Customize → Connectors → «Add custom connector»: вставте адресу й увійдіть
https://homin.ua/mcpЯк це виглядає в асистенті
n8n, Make, Zapier і вебхуки.
Шаблони сценаріїв: від таблиці до аудіо в каналі. Готових модулів поки немає — підключайте через HTTP-запит до API і вебхуки.
ШаблонRSS → дайджест новин голосом
ШаблонCRM → персональний голосовий дзвінок
ВебхукиПодії генерацій і бюджету, підпис HMAC, до 3 повторів
generation.completedgeneration.failedbudget.thresholdPOST https://your.app/hooks/homin X-HOMIN-Event: generation.completed X-HOMIN-Signature: sha256=9f86d081… X-HOMIN-Timestamp: 1760270402 X-HOMIN-Delivery: clx… { "id": "evt_3f9a1c0b7d2e4f6a8b1c2d3e", "type": "generation.completed", "created": 1760270400, "data": { "id": "clw9k2m4x0001", "voice": "solomiia", "model": "pro", "chars": 640, "credits": 13, "seconds": 41.2, "url": "https://homin.ua/audio/file/clw9k2m4x0001.mp3?exp=…&sig=…" } }Документація вебхуків
Події на ваш сервер — з підписом і повторами.
HOMIN надсилає POST із JSON на вашу HTTPS-адресу, коли генерація готова чи не вдалася або ключ доходить порогу бюджету. Вебхуки належать простору, а керують ними в кабінеті власник і адміністратори з доступом до ключів.
Події та підпис
HMAC-SHA256| Подія | Коли | data |
|---|---|---|
generation.completed | аудіо готове | id, voice (slug), model (neo|pro|live), chars, credits, seconds|null, url|null |
generation.failed | синтез не вдався або генерацію закрито | id, error |
budget.threshold | ключ дійшов 80 % бюджету, вичерпав його або запит не вмістився в залишок | scope (key), key {id, name}, threshold (80|100), level (warning|exhausted), spent, budget, remaining |
webhook.test | тест із кабінету | endpoint |
Тіло — JSON { id, type, created, data }; id події однаковий для всіх ендпойнтів і повторів, created — Unix-секунди.
X-HOMIN-Event— тип подіїX-HOMIN-Signature— sha256=HMAC(секрет, timestamp.body)X-HOMIN-Timestamp— час підпису цієї спроби, Unix-секунди; розходиться з вашим годинником більш ніж на 5 хв — відхиляйтеX-HOMIN-Delivery— id доставки, один для всіх спроб, — для звірки з журналом у кабінеті# 1. перевірити підпис: body.json — сире тіло запиту, TS — X-HOMIN-Timestamp printf '%s.' "$TS" | cat - body.json \ | openssl dgst -sha256 -hmac "$HOMIN_WEBHOOK_SECRET" | awk '{print "sha256=" $NF}' # має збігтися з X-HOMIN-Signature # 2. надіслати на свій приймач підписаний тест TS=$(date +%s) BODY='{"id":"evt_test_local","type":"webhook.test","created":'"$TS"',"data":{"endpoint":"local"}}' SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$HOMIN_WEBHOOK_SECRET" | awk '{print $NF}') curl -sS https://your.app/hooks/homin \ -H 'Content-Type: application/json' \ -H 'User-Agent: HOMIN-Webhooks/1.0' \ -H 'X-HOMIN-Event: webhook.test' \ -H 'X-HOMIN-Delivery: test_local' \ -H "X-HOMIN-Timestamp: $TS" \ -H "X-HOMIN-Signature: sha256=$SIG" \ --data-binary "$BODY"
Коди збоїв і пороги бюджету
generation.failed— error — лише публічний код:provider_rejectedprovider_busyprovider_quotaprovider_authprovider_unavailablevoice_unavailabletext_too_longstream_failedgateway_timeoutupstream_failedmargin_floorstorage_failedclosed_by_staffgeneration_failedЗначення — як у «Коди помилок» вище; stream_failed — потік обірвався, storage_failed — аудіо не збереглося, gateway_timeout — шлюз не прозвітував вчасно, closed_by_staff — генерацію закрила підтримка, generation_failed — усе інше.
budget.threshold- warning (80 %) і exhausted (100 %) приходять по одному разу на кожне значення бюджету; поріг фіксується в момент резерву кредитів.
- Якщо один запит перетнув обидва пороги, приходить лише exhausted.
- exhausted приходить і на перший запит, що не вмістився в залишок, коли вже витрачено щонайменше 80 %; сам запит отримує quota_exceeded.
- Знову пороги спрацюють лише після зміни бюджету ключа; повернення кредитів за невдалі генерації їх не скидає.
- spent, budget і remaining — у кредитах; ключі без бюджету й генерації в студії подій не дають.
Доставка й повтори
- Доставка at-least-once: дедуплікуйте за id у тілі — він підписаний, на відміну від X-HOMIN-Delivery; 2xx відповідайте одразу, а обробку робіть асинхронно.
- Успіх — відповідь 2xx за 10 с; 3xx, 4xx, 5xx, таймаут чи помилка мережі — невдача. Редиректів не виконуємо, тіло відповіді не читаємо.
- Невдалу спробу повторюємо через 1 хв, 10 хв і 1 год (±20 %) — разом до 4 спроб із тим самим id і X-HOMIN-Delivery.
- Невдалу доставку можна повторити з журналу в кабінеті: одна спроба з тим самим id і свіжим url, поки тіло доставки зберігається (7 днів).
- Після 20 остаточно невдалих доставок поспіль вебхук вимикається, а власникам простору приходить лист; події за час вимкнення не зберігаються.
- Вебхук, привʼязаний до ключа, вимикається разом із відкликанням ключа.
- Порядок доставок не гарантовано — орієнтуйтеся на created.
- З одного простору одночасно йде не більше 2 доставок, решта чекає в черзі: повільний приймач затримує насамперед ваші ж події.
- Тест із кабінету надсилає webhook.test із тим самим підписом, одразу й без повторів. На невідомі типи подій відповідайте 2xx.
Посилання url підписується заново для кожної спроби й діє 24 години. Свіже беріть з поля audioUrl у GET /generations/{id} — від тієї ж бази, що REST API, з ключем із правом «читання». audioUrl — відносний шлях: додайте до нього адресу сайту.
Як підключити
x-homin-generation відповіді 200 на запит синтезу; GET /generations/{id} від бази REST API віддає її статус і свіже посилання на аудіо. У generation.failed id збігається із цим заголовком, лише якщо збій стався вже після початку відповіді 200; коли синтез одразу відповів помилкою, id генерації у відповіді немає.Якщо не приходять
Код у журналі
http_3xx–5xx— приймач відповів не 2xx — у журналі видно сам код. 401 найчастіше означає інший секрет або тіло, змінене до перевірки підпису; 3xx — редирект, його не виконуємо.timeout— приймач не відповів вчасно — 10 с на всю спробу. Відповідайте 2xx одразу, а обробку виносьте поза запит.send_failed— зʼєднання не вдалося — приймач відмовив чи обірвав його або має недійсний TLS-сертифікат.dns_failed— домен не розвʼязується — немає записів A чи AAAA або DNS не відповів вчасно.url_private— адреса в приватному діапазоні — домен веде в приватну чи внутрішню мережу. Приймач має бути доступний з інтернету.secret_undecryptable— секрет не розшифровується на нашому боці — натисніть «Новий секрет» і оновіть його на приймачі.endpoint_disabled— вебхук вимкнули, поки доставка чекала в черзі, — увімкніть його й повторіть доставку.ops_cancelled— доставку скасувала підтримка під час аварійної зупинки — повторіть її кнопкою «Повторити» в журналі.Чому вебхук вимкнувся
too_many_failures— 20 остаточно невдалих доставок поспіль; власникам простору приходить лист. Виправте приймач і перевірте його «Тестом».key_revoked— ключ, до якого привʼязано вебхук, відкликано: у «Змінити» оберіть інший ключ або всі події простору й збережіть.Потік у дзвінок — без проміжних файлів.
HOMIN Live віддає аудіо потоком у Twilio, SIP/Asterisk, LiveKit і Pipecat. Перша фраза за ~300 мс.
<!-- TwiML: з'єднати дзвінок із HOMIN Live --> <Response> <Connect> <Stream url="wss://live.homin.ua/twilio"> <Parameter name="voice" value="bohdan"/> <Parameter name="agent" value="agent_support"/> </Stream> </Connect> </Response>