Wavesift API v1
Базовий URL https://api.wavesift.com/v1
Промпт для AI-агента OpenAPI JSON
Формат: JSON у camelCase, enum-значення у snake_case, час в ISO-8601 UTC, помилки як RFC 7807 application/problem+json.
Розділ 1

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

Серверна інтеграція працює через API-ключ, прив'язаний до вашого облікового запису. Ключ виглядає як atk_… (68 символів), передається в заголовку X-Api-Key у кожному запиті й діє замість логіна: усі ресурси створюються від імені вашого акаунта і підпадають під ліміти його тарифу. Ключ показується один раз при створенні, у нас зберігається лише його хеш. Можна задати термін дії, відкликати будь-коли, тримати до 5 активних ключів.

Порядок: зареєструвати акаунт, увійти, створити ключ із сесії входу. Створення й відкликання ключів працює лише з Bearer-токеном: такий запит, підписаний іншим ключем, отримає 403.

Кожен новий акаунт автоматично отримує Trial на 14 днів без квот тарифу. Після 14 днів акаунт переходить на базовий план, ключі продовжують працювати. Продовжити trial чи перевести на платний план можемо з нашого боку.
Ключ — секрет рівня пароля: тримайте його у сховищі секретів, не комітьте в код, не передавайте у query string. У разі витоку відкличте його через DELETE /user/api-keys/{id} і створіть новий.
ЗаголовокКоли використовуватиЖиве
X-Api-Key: atk_…Уся інтеграція: транскрипції, самарі, пресети, підписка.до expiresAt або відкликання
Authorization: Bearer …Лише керування ключами. Токен видає POST /auth/login.15 хвилин
Cookie: refresh_tokenПродовжити сесію без пароля через POST /auth/refresh (curl: -c jar.txt -b jar.txt).httpOnly
POST/auth/register Реєстрація акаунта
без автентифікаціїapplication/json

Відповідь та сама, що в логіні: access-токен на 15 хвилин і об'єкт користувача.

Тіло запиту application/json
ПолеТипОпис
emailstringобов'язковеЛогін акаунта, має бути унікальним.
passwordstringобов'язковеПароль, проходить перевірку складності.
usernamestringнеобов'язковеВідображуване ім'я.
Заголовки
ЗаголовокЗначення
Content-Typeapplication/jsonобов'язковий

Автентифікація не потрібна. Тіло: JSON з полями з вкладки «Параметри».

200 application/json
ПолеТипОпис
accessTokenstringJWT для заголовка Authorization: Bearer, живе 15 хвилин.
userUserСтворений акаунт, модель User.

Разом із відповіддю сервер ставить httpOnly-cookie refresh_token.

КодКолиЩо робити
400Email уже зайнятий або пароль не проходить перевірку, причина в detail.Виправити дані.
Запитcurl
curl -sS https://api.wavesift.com/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{"email":"ops@example.com","password":"…","username":"ops"}'
Відповідь200 OKapplication/json
{
  "accessToken": "eyJhbGciOiJIUzI1NiIs…",
  "user": {
    "id": "01a06f11-…",
    "email": "ops@example.com",
    "username": "ops",
    "role": "client",
    "status": "active",
    "createdAt": "2026-09-05T11:30:02.114Z",
    "updatedAt": "2026-09-05T11:30:02.114Z"
  }
}
Помилка400 Bad Requestapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "<причина: email зайнятий або слабкий пароль>"
}
POST/auth/login Вхід і Bearer-токен
без автентифікаціїapplication/json

Логін потрібен для керування ключами. Разом із відповіддю сервер ставить httpOnly-cookie refresh_token; продовжити сесію без пароля можна через POST /auth/refresh з цією cookie.

Тіло запиту application/json
ПолеТипОпис
emailstringобов'язковеEmail акаунта.
passwordstringобов'язковеПароль.
Заголовки
ЗаголовокЗначення
Content-Typeapplication/jsonобов'язковий

Щоб зберегти cookie для POST /auth/refresh, додайте до curl -c jar.txt, а в наступних запитах -b jar.txt.

200 application/json
ПолеТипОпис
accessTokenstringJWT для заголовка Authorization: Bearer, живе 15 хвилин.
userUserАкаунт, модель User.
КодКолиЩо робити
401Невірний email або пароль.Перевірити дані входу.
Запитcurl
curl -sS https://api.wavesift.com/v1/auth/login \
  -H "Content-Type: application/json" \
  -c jar.txt \
  -d '{"email":"ops@example.com","password":"…"}'
Відповідь200 OKapplication/json
{
  "accessToken": "eyJhbGciOiJIUzI1NiIs…",
  "user": {
    "id": "01a06f11-…",
    "email": "ops@example.com",
    "username": "ops",
    "role": "client",
    "status": "active",
    "createdAt": "…",
    "updatedAt": "…"
  }
}
Помилка401 Unauthorizedapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
  "title": "Unauthorized",
  "status": 401
}
POST/user/api-keys Створити API-ключ
Authorization: Bearerapplication/json

Створити ключ для інтеграції. Поле apiKey у відповіді показується лише цього разу, далі доступний тільки префікс. Токен для цього запиту беріть з POST /auth/login.

Тіло запиту application/json
ПолеТипОпис
namestringобов'язковеНазва ключа. У відповіді повертається як partnerName.
expiresAtdatetimeнеобов'язковеТермін дії, ISO-8601 UTC. Без нього ключ безстроковий.
Заголовки
ЗаголовокЗначення
AuthorizationBearer <accessToken>обов'язковий
Content-Typeapplication/jsonобов'язковий

Запит, підписаний API-ключем замість Bearer, отримає 403.

200 application/json
ПолеТипОпис
apiKeystringПовне значення ключа. Збережіть одразу, повторно не показується.
keyApiKeyМетадані ключа, модель ApiKey: id для відкликання, keyPrefix, partnerName, expiresAt, isActive.
КодКолиЩо робити
400expiresAt у минулому.Виправити дату.
403Запит підписаний API-ключем, а не Bearer.Увійти через POST /auth/login.
409Уже 5 активних ключів.Відкликати непотрібний ключ.
Запитcurl
curl -sS https://api.wavesift.com/v1/user/api-keys \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Production","expiresAt":"2027-09-01T00:00:00Z"}'
Відповідь200 OKapplication/json
{
  "key": {
    "id": "01a06f1c-…",
    "ownerUserId": "01a06f11-…",
    "ownerEmail": "ops@example.com",
    "partnerName": "Production",
    "keyPrefix": "atk_4b0zgyEB",
    "bypassLimits": false,
    "isActive": true,
    "expiresAt": "2027-09-01T00:00:00Z",
    "revokedAt": null,
    "lastUsedAt": null,
    "createdAt": "2026-09-05T11:31:40.902Z"
  },
  "apiKey": "atk_4b0zgyEB…"
}
Помилка403 Forbiddenapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.4",
  "title": "Forbidden",
  "status": 403,
  "detail": "<причина: керування ключами потребує Bearer>"
}
GET/user/api-keys Список ключів
X-Api-Key або Bearer

Свої ключі, найновіші першими. Raw-значень тут немає, лише префікс і дати.

Без параметрів.

Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…або Bearer
200 application/json
ПолеТипОпис
itemsApiKey[]Масив об'єктів ApiKey, найновіші першими.
КодКолиЩо робити
401Ключ або токен відсутній, невірний, відкликаний або прострочений.Перевірити автентифікацію.
Запитcurl
curl -sS https://api.wavesift.com/v1/user/api-keys \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKapplication/json
{
  "items": [
    {
      "id": "01a06f1c-…",
      "ownerUserId": "…",
      "ownerEmail": "ops@example.com",
      "partnerName": "Production",
      "keyPrefix": "atk_4b0zgyEB",
      "bypassLimits": false,
      "isActive": true,
      "expiresAt": "2027-09-01T00:00:00Z",
      "revokedAt": null,
      "lastUsedAt": "2026-09-05T12:02:11.008Z",
      "createdAt": "…"
    }
  ]
}
Помилка401 Unauthorizedapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
  "title": "Unauthorized",
  "status": 401
}
DELETE/user/api-keys/{id} Відкликати ключ
Authorization: Bearer

Діє миттєво й незворотно. У відповіді той самий об'єкт ключа з revokedAt та isActive: false.

Шлях
ПолеТипОпис
iduuidобов'язковеid ключа зі списку, не сам ключ.
Заголовки
ЗаголовокЗначення
AuthorizationBearer <accessToken>обов'язковий

Без тіла.

200 application/json

Об'єкт ApiKey з isActive: false і заповненим revokedAt.

КодКолиЩо робити
403Запит підписаний API-ключем.Увійти через POST /auth/login.
404Ключ не ваш або не існує.Перевірити id.
Запитcurl
curl -sS -X DELETE https://api.wavesift.com/v1/user/api-keys/$KEY_ID \
  -H "Authorization: Bearer $ACCESS_TOKEN"
Відповідь200 OKapplication/json
{
  "id": "01a06f1c-…",
  "partnerName": "Production",
  "keyPrefix": "atk_4b0zgyEB",
  "isActive": false,
  "revokedAt": "2026-09-05T12:10:33.510Z",
  … решта полів як у моделі ApiKey
}
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
GET/user/me Перевірити ключ
X-Api-Key

Повертає акаунт, від імені якого діє ключ. Зручно як перший запит інтеграції і як перевірка живості.

Без параметрів.

Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
200 application/json

Об'єкт User.

КодКолиЩо робити
401Ключ відсутній, невірний, відкликаний або прострочений.Перевірити ключ або створити новий.
Запитcurl
curl -sS https://api.wavesift.com/v1/user/me \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKapplication/json
{
  "id": "01a06f11-…",
  "email": "ops@example.com",
  "username": "ops",
  "role": "client",
  "status": "active",
  "createdAt": "…",
  "updatedAt": "…"
}
Помилка401 Unauthorizedapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
  "title": "Unauthorized",
  "status": 401
}
Розділ 2

Промпт для AI-агента розробника

Якщо інтеграцію пише Claude Code, Cursor чи інший агент, дайте йому цей текст як завдання. У ньому весь контракт стиснуто до інструкції англійською: базова адреса, автентифікація, п'ять кроків, опитування, домовленість про канали, коди помилок і вимоги до реалізації. Мову й фреймворк агент візьме з вашого проєкту. Ключ підставляти не треба, він читається зі змінної середовища WAVESIFT_API_KEY.

Блок промптуЩо фіксує
BASE URL · SPECАдреса API і посилання на OpenAPI JSON як джерело правди.
AUTH · FORMATЗаголовок X-Api-Key зі змінної середовища, camelCase, ISO-8601, RFC 7807.
FLOW 1–5Завантаження, очікування, транскрипт, самарі, очікування самарі. Канали: лівий = учасник 1, правий = учасник 2.
ERROR HANDLINGЩо робити на кожен код, backoff для 5xx, X-Correlation-Id у логах.
REQUIREMENTSЗберігати оригінал аудіо, ідемпотентність, тести, CLI на один файл.
OpenAPI JSON
ПромптEnglish · plain text
Integrate our two-channel call recordings with the Wavesift HTTP API. Build a small, well-tested client module (or CLI) in this project's primary language and follow the contract below exactly — do not invent endpoints or fields.

BASE URL: https://api.wavesift.com/v1
SPEC: the exact machine-readable contract (request/response schemas, enums, status codes) is the OpenAPI document at https://api.wavesift.com/docs/public/openapi.json (the human-readable contract is at /docs). Fetch it first and treat it as the source of truth where this text is less specific; do not use endpoints that are not in it.
AUTH: send header `X-Api-Key: <key>` on every request. Read the key from the env var WAVESIFT_API_KEY. Never log it, never commit it, never put it in a URL. Keys are created once by a human from a login session (POST /auth/login → Bearer token → POST /user/api-keys `{ "name", "expiresAt"? }` → `apiKey` is shown once); the integration itself must not create or rotate keys.
FORMAT: JSON with camelCase fields; enum values are lowercase snake_case strings; timestamps are ISO-8601 UTC. Errors are RFC 7807 `application/problem+json` with `status` and `detail`.

FLOW (one recording = one transcription):
1. Upload: POST /transcriptions as multipart/form-data with field `system_file` (the stereo recording; accepted extensions: wav, flac, mp3, m4a, m4b, aac, ogg, opus, wma, webm, mp4, mkv), optional `title` (put our call id here) and `language` (ISO code like "uk", or "auto"; default auto). Response 200 is the transcription object with `id`, `kind: "upload"` and `status: "queued"`. Body limit is 6 GB per request. Batch alternative: POST /transcriptions/bulk with up to 50 file fields → `{ items: [{ index, fileName, transcription | null, error | null }] }` (partial success is normal).
   Channel convention: LEFT channel = participant 1 (in our case the operator), RIGHT channel = participant 2 (the customer). The server splits the channels automatically and labels segments `speakerLabel: "SPEAKER_1"` (left) and `"SPEAKER_2"` (right); these labels are fixed once the transcription is `completed`. If both channels carry the same mix there is no split: right after `completed` the segments have `speakerLabel: null`, then the server runs voice diarization and fills `SPEAKER_N` in order of first appearance; `audioDeletedAt` becoming non-null signals that this step is done.
2. Wait: poll GET /transcriptions/{id} every 5–10 s (or subscribe to GET /transcriptions/{id}/events, text/event-stream, events `status`/`progress`). `status` is one of queued | processing | completed | failed. On `failed` read `errorMessage` and re-upload; do not retry in a tight loop.
3. Read the transcript: GET /transcriptions/{id}/segments → `{ items: [{ id, start, end, text, source, speakerUserId, speakerLabel }] }` ordered by `start` (seconds). Or GET /transcriptions/{id}/markdown for text/markdown with timecodes and speaker tags like `[OTHER-SPEAKER_1]` (404 until completed).
4. Summary: POST /transcriptions/{id}/summaries with JSON `{ "presetId": "<guid>" }`. Only valid when the transcription is `completed` (otherwise 409). List presets with GET /summary-presets → `{ items: [{ id, name, prompt, isGlobal, ... }] }`; the ready-made two-speaker call preset is named "Розбір дзвінка КЦ" (id 0198c0de-0000-7000-8000-000000000005). To use our own instructions create a preset once: POST /summary-presets `{ "name", "prompt" }` (the server prepends a short Ukrainian preamble describing the transcript format and appends the transcript itself; do not include the transcript in the prompt; state the output language explicitly if it is not Ukrainian) and reuse its id.
5. Wait for the summary: poll GET /summaries/{summaryId} every 5 s until `status: "completed"`, then read `markdown`. `failed` carries `errorMessage`.

OTHER ENDPOINTS: GET /user/me (identity check), GET /transcriptions?page=&limit=&status=&kind=&q= (own history, `{ items, totalCount }`; `kind` is `upload` for single-file uploads and `meeting` when both mic_file and system_file were sent), GET /transcriptions/{id}/summaries (summary history), DELETE /transcriptions/{id} (204), GET /subscription/current (plan and usage; 0 in the plan and null in the remaining fields mean unlimited).

ERROR HANDLING: 400 → fix the request; 401 → the key is missing/invalid/expired, stop and alert a human (do not retry); 403 → wrong resource id or wrong auth method; 404 → unknown id or transcript not ready yet; 409 → business rule (transcription not completed, plan limit on file size / minutes / presets) — wait or surface it; 413 → file over 6 GB (the body may be an HTML page from the proxy); 5xx → retry with exponential backoff (max 5 attempts) and include the `X-Correlation-Id` response header in logs. Set the correlation header yourself (a UUID per call) so we can trace requests.

REQUIREMENTS: keep our original audio (the server deletes source audio after processing); store `transcriptionId`, `summaryId`, transcript markdown and summary markdown against our call record; make upload and polling idempotent per call id; unit-test the JSON mapping and the status machine with recorded fixtures; add a CLI/command that runs the whole flow for one file and prints the summary.
Розділ 3

Швидкий старт

Одна розмова проходить п'ять кроків. Ключ уже створено в розділі 1, решту робить ваша інтеграція. Кожен крок показаний однією командою. Змінні: $API_KEY ваш ключ, $ID id транскрипції з кроку 2, $SUMMARY_ID id самарі з кроку 5.

1

Перевірити ключ

Перший запит інтеграції. Повертає акаунт, від імені якого діє ключ. 401 означає, що ключ невірний, відкликаний або прострочений.

ЗапитGET /user/me
curl -sS https://api.wavesift.com/v1/user/me \
  -H "X-Api-Key: $API_KEY"
2

Завантажити запис

Стерео-файл, один канал на учасника. Відповідь приходить одразу зі статусом queued та id.

ЗапитPOST /transcriptions
curl -sS https://api.wavesift.com/v1/transcriptions \
  -H "X-Api-Key: $API_KEY" \
  -F "system_file=@call-48213.wav" \
  -F "language=uk"
3

Дочекатися статусу

Опитуйте раз на 5–10 секунд до completed або failed. Замість опитування є SSE-потік GET /transcriptions/{id}/events.

ЗапитGET /transcriptions/{id}
curl -sS https://api.wavesift.com/v1/transcriptions/$ID \
  -H "X-Api-Key: $API_KEY"
4

Забрати транскрипт

Сегменти з таймкодами й мітками мовців. Той самий текст як markdown доступний через GET /transcriptions/{id}/markdown.

ЗапитGET /transcriptions/{id}/segments
curl -sS https://api.wavesift.com/v1/transcriptions/$ID/segments \
  -H "X-Api-Key: $API_KEY"
5

Замовити самарі

Вкажіть presetId: готовий «Розбір дзвінка КЦ» або власний пресет. Результат забирається з GET /summaries/{summaryId}, коли статус completed.

ЗапитPOST /transcriptions/{id}/summaries
curl -sS https://api.wavesift.com/v1/transcriptions/$ID/summaries \
  -H "X-Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"presetId":"0198c0de-0000-7000-8000-000000000005"}'
Розділ 4

Домовленість про канали

Основний сценарій: стерео-файл, один канал на учасника. Сервер визначає, що канали містять різних мовців, розділяє їх і транскрибує окремо. Обидва мовці мають source: "other" і розрізняються полем speakerLabel. Мітки прив'язані до каналів і після completed не змінюються. У прикладах учасник 1 — оператор, учасник 2 — клієнт, але це лише ілюстрація.

Розділення вмикається автоматично, коли активність каналів чергується, як у живій розмові. Якщо в обох каналах один і той самий мікс або обидва канали безперервно активні одночасно, файл обробляється як один потік: одразу після completed сегменти без speakerLabel, потім сервер запускає діаризацію за голосом і проставляє SPEAKER_1, SPEAKER_2, … у порядку першої появи. Ознака, що цей крок завершено: audioDeletedAt не null.

Із двома окремими файлами (mic_file + system_file) розділення детерміноване: сегменти оператора приходять із source: "you", клієнта з source: "other", а kind транскрипції буде meeting, не upload.

L (0)
Учасник 1 → speakerLabel: SPEAKER_1
R (1)
Учасник 2 → speakerLabel: SPEAKER_2
1 потік
null → після діаризації SPEAKER_N
Розділ 5

Транскрипції

Один запит на одну розмову. Відповідь приходить одразу зі статусом queued; обробку виконує пул агентів, тому результат забирається окремо. Формати за розширенням файлу: wav, flac, mp3, m4a, m4b, aac, ogg, opus, wma, webm, mp4, mkv; інше розширення дає 400. Рекомендуємо WAV або FLAC, 16 kHz і вище.

POST/transcriptions Завантажити запис
X-Api-Keymultipart/form-dataтіло до 6 ГБ

Завантажити один запис. У відповіді об'єкт транскрипції зі статусом queued, далі його id використовується в усіх наступних запитах.

Поля форми multipart/form-data
ПолеТипОпис
system_filefileтак *Аудіофайл розмови. * Хоча б один із system_file / mic_file.
mic_filefileніДругий трек, коли оператор і клієнт уже записані окремо. У стерео-сценарії не передається.
titlestringніДовільна назва, зручно класти ваш ID дзвінка.
languagestringніISO-код (uk, en, ru, …) або auto. За замовчуванням auto.
mic_offset_msintegerніЗсув початку треку в мс, коли треки стартують не одночасно.
system_offset_msintegerніТе саме для системного треку.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
Content-Typemultipart/form-dataставить curl

Приклад праворуч показує стерео-файл. Для двох моно-файлів передайте mic_file=@operator.wav і system_file=@client.wav замість одного system_file. Тіло до 6 ГБ на запит.

200 application/json

Об'єкт Transcription. Одразу після завантаження заповнені лише ідентифікатор, статус і те, що ви передали; решта полів отримає значення під час обробки.

ПолеТипЩо означає
iduuidІдентифікатор для всіх наступних запитів.
kindenumupload для одного файлу, meeting для двох треків.
statusenumТут завжди queued.
hasSystemTrack · hasMicTrackbooleanЯкі треки отримано.
systemFileSizeBytes · micFileSizeBytesinteger | nullРозмір файлів у байтах.
createdAtdatetimeМомент завантаження.
КодКолиЩо робити
400Немає файлу або непідтримуване розширення.Виправити запит.
409Перевищено ліміт плану на розмір файлу або хвилини.Перевірити GET /subscription/current.
413Тіло більше 6 ГБ. Відповідь може прийти від проксі з HTML-тілом.Стиснути у FLAC або розбити файл.
Запитcurl · стерео-файл
curl -sS https://api.wavesift.com/v1/transcriptions \
  -H "X-Api-Key: $API_KEY" \
  -F "system_file=@call-2026-09-05-1432.wav" \
  -F "title=Дзвінок #48213, оператор Іванова" \
  -F "language=uk"
Відповідь200 OKapplication/json
{
  "id": "01a06f3e-7c1a-7b52-9d2e-3f0c1a9d8e11",
  "kind": "upload",
  "status": "queued",
  "title": "Дзвінок #48213, оператор Іванова",
  "language": "uk",
  "detectedLanguage": null,
  "whisperModel": null,
  "durationSeconds": null,
  "hasMicTrack": false,
  "hasSystemTrack": true,
  "micFileSizeBytes": null,
  "systemFileSizeBytes": 18432044,
  "progressStage": null,
  "progressPercent": null,
  "errorMessage": null,
  "startedAt": null,
  "completedAt": null,
  "audioDeletedAt": null,
  "createdAt": "2026-09-05T11:32:07.412Z"
}
Помилка409 Conflictapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
  "title": "Conflict",
  "status": 409,
  "detail": "Monthly audio limit exceeded: 3012.4/3000 min used"
}
POST/transcriptions/bulk Пакетне завантаження
X-Api-Keymultipart/form-dataдо 50 файлів

До 50 файлів за раз, кожен стає окремою транскрипцією за стерео-сценарієм; title дорівнює імені файлу. Помилка одного файлу не валить пакет: у відповіді буде error навпроти конкретного файлу.

Поля форми multipart/form-data
ПолеТипОпис
будь-яке ім'яfile1–50 файлівІмена полів не важливі, кожен файл стає окремою транскрипцією.
languagestringніСпільний для всіх файлів пакета.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
Content-Typemultipart/form-dataставить curl
200 application/json
ПолеТипОпис
items[].indexintegerПорядковий номер файлу в запиті.
items[].fileNamestringІм'я файлу, воно ж title транскрипції.
items[].transcriptionTranscription | nullСтворена транскрипція, модель. null, якщо файл відхилено.
items[].errorstring | nullПричина відхилення конкретного файлу.
КодКолиЩо робити
400Жодного файлу або більше 50.Розбити пакет.

Ліміти плану на окремий файл не дають 4xx для всього пакета, а потрапляють в error відповідного елемента.

Запитcurl
curl -sS https://api.wavesift.com/v1/transcriptions/bulk \
  -H "X-Api-Key: $API_KEY" \
  -F "language=uk" \
  -F "f1=@call-48213.wav" \
  -F "f2=@call-48214.wav"
Відповідь200 OKapplication/json
{
  "items": [
    {
      "index": 0,
      "fileName": "call-48213.wav",
      "transcription": { "id": "01a06f40-…", "status": "queued",  },
      "error": null
    },
    {
      "index": 1,
      "fileName": "call-48214.wav",
      "transcription": null,
      "error": "Monthly audio limit exceeded: 3012.4/3000 min used"
    }
  ]
}
Помилка400 Bad Requestapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "<причина: немає файлів або більше 50>"
}

Статус обробки

Опитуйте раз на 5–10 секунд до термінального статусу або підпишіться на SSE. Час обробки залежить від довжини запису й черги агентів.

queued processing completedабоfailed
statusЗначенняЩо робити
queuedУ черзі, агент ще не взяв.Чекати.
processingОбробляється. Дивіться progressStage / progressPercent.Чекати, показувати прогрес.
completedГотово. Заповнені durationSeconds, detectedLanguage, completedAt.Забирати транскрипт, замовляти самарі.
failedПомилка, причина в errorMessage.Завантажити файл повторно.
GET/transcriptions/{id} Статус транскрипції
X-Api-Key

Поточний стан транскрипції. Це основний запит для опитування: повторюйте його раз на 5–10 секунд до термінального статусу.

Шлях
ПолеТипОпис
iduuidобов'язковеid з відповіді на завантаження.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

Без тіла. Не опитуйте частіше, ніж раз на 5 секунд.

200 application/json

Об'єкт Transcription. Поля, на які варто дивитися під час опитування:

ПолеТипЩо означає
statusenumТермінальні значення completed і failed.
progressStagestring | nullРядок стадії для відображення, наприклад TRANSCRIBE_START, DONE.
progressPercentinteger | null0–100 під час processing.
errorMessagestring | nullПричина при failed.
completedAtdatetime | nullКоли транскрипція завершена.
audioDeletedAtdatetime | nullКоли видалено оригінал. Для одного потоку також означає, що діаризація за голосом завершена.
КодКолиЩо робити
403Транскрипція іншого акаунта.Перевірити id і ключ.
404Невідомий id.Перевірити id.
Запитcurl
curl -sS https://api.wavesift.com/v1/transcriptions/$ID \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKcompleted
{
  "id": "01a06f3e-7c1a-7b52-9d2e-3f0c1a9d8e11",
  "kind": "upload",
  "status": "completed",
  "title": "Дзвінок #48213, оператор Іванова",
  "language": "uk",
  "detectedLanguage": "uk",
  "whisperModel": "large-v3-turbo",
  "durationSeconds": 187.4,
  "hasMicTrack": false,
  "hasSystemTrack": true,
  "micFileSizeBytes": null,
  "systemFileSizeBytes": 18432044,
  "progressStage": "DONE",
  "progressPercent": 100,
  "errorMessage": null,
  "startedAt": "2026-09-05T11:32:31.006Z",
  "completedAt": "2026-09-05T11:34:12.887Z",
  "audioDeletedAt": "2026-09-05T11:34:12.901Z",
  "createdAt": "2026-09-05T11:32:07.412Z"
}
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
GET/transcriptions/{id}/events Статус потоком (SSE)
X-Api-Keytext/event-stream

Перша подія — знімок status, далі progress/status до термінального статусу, після чого потік закривається. Перепідключатися можна будь-коли. stage — довільний рядок стадії для відображення.

Шлях
ПолеТипОпис
iduuidобов'язковеТранскрипція, за якою стежити.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

У curl вимкніть буферизацію прапорцем -N, щоб бачити події одразу.

200 text/event-stream
eventПоля dataОпис
statustype, status, stage, percent, messageЗнімок статусу. Перша подія завжди така, остання несе термінальний статус.
progresstype, stage, percentПрогрес обробки; status тут null.
КодКолиЩо робити
403Транскрипція іншого акаунта.Перевірити id і ключ.
404Невідомий id.Перевірити id.
Запитcurl
curl -sN https://api.wavesift.com/v1/transcriptions/$ID/events \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKtext/event-stream
event: status
data: {"type":"status","status":"processing","stage":null,"percent":null,"message":null}

event: progress
data: {"type":"progress","status":null,"stage":"TRANSCRIBE_START","percent":42,"message":null}

event: status
data: {"type":"status","status":"completed","stage":"DONE","percent":100,"message":null}
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
GET/transcriptions/{id}/segments Транскрипт як сегменти
X-Api-Key

Сегменти впорядковані за часом початку. start і end у секундах від початку запису.

Шлях
ПолеТипОпис
iduuidобов'язковеТранскрипція зі статусом completed.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

Без тіла.

200 application/json

{ items: Segment[] }. Ключові поля сегмента:

ПолеОпис
sourceyou — трек mic_file; other — трек system_file (у стерео-сценарії обидва мовці тут).
speakerLabelСтерео: SPEAKER_1 = лівий канал, SPEAKER_2 = правий. Один потік: null до завершення діаризації за голосом, потім SPEAKER_N у порядку першої появи.
speakerUserIdДля серверних інтеграцій завжди null (використовується голосовими профілями інших продуктів).
КодКолиЩо робити
403Чужа транскрипція.Перевірити id і ключ.
404Невідомий id.Перевірити id.
Запитcurl
curl -sS https://api.wavesift.com/v1/transcriptions/$ID/segments \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKстерео-сценарій
{
  "items": [
    {
      "id": "01a06f45-…",
      "start": 0.42,
      "end": 3.91,
      "text": "Добрий день, компанія «Ортекс», оператор Марина.",
      "source": "other",
      "speakerUserId": null,
      "speakerLabel": "SPEAKER_1"
    },
    {
      "id": "01a06f45-…",
      "start": 4.10,
      "end": 7.55,
      "text": "Вітаю, я щодо замовлення сорок вісім тисяч двісті тринадцять.",
      "source": "other",
      "speakerUserId": null,
      "speakerLabel": "SPEAKER_2"
    }
  ]
}
Помилка403 Forbiddenapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.4",
  "title": "Forbidden",
  "status": 403
}
GET/transcriptions/{id}/markdown Транскрипт як текст
X-Api-Keytext/markdown

Той самий транскрипт як готовий текст із таймкодами й мітками мовців. Саме цей текст сервер передає моделі для самарі. Після діаризації за голосом документ перегенеровується, тож мітки тут і в сегментах збігаються.

Шлях
ПолеТипОпис
iduuidобов'язковеТранскрипція зі статусом completed.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

Щоб зберегти у файл, додайте до curl -o call-48213.md.

200 text/markdown; charset=utf-8

Рядок виду **[hh:mm:ss] [SOURCE-SPEAKER_N]** текст на кожен сегмент. SOURCE це OTHER для system_file і YOU для mic_file.

КодКолиЩо робити
404Транскрипт ще не готовий (статус не completed) або невідомий id.Дочекатися completed.
Запитcurl
curl -sS https://api.wavesift.com/v1/transcriptions/$ID/markdown \
  -H "X-Api-Key: $API_KEY" \
  -o call-48213.md
Відповідь200 OKtext/markdown
# Транскрипт мітінгу

**[00:00:00] [OTHER-SPEAKER_1]** Добрий день, компанія «Ортекс», оператор Марина.

**[00:00:04] [OTHER-SPEAKER_2]** Вітаю, я щодо замовлення сорок вісім тисяч двісті тринадцять.

**[00:00:07] [OTHER-SPEAKER_1]** Зараз перевірю. Підкажіть, будь ласка, прізвище отримувача.
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
GET/transcriptions Список транскрипцій
X-Api-Key

Список власних транскрипцій, найновіші першими. Усі параметри необов'язкові.

Query
ПолеТипОпис
pageintegerніНомер сторінки, від 1.
limitintegerніРозмір сторінки, до 1000.
statusenumніqueued | processing | completed | failed.
kindenumніupload для одного файлу, meeting для двох.
qstringніПошук по назві.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

Query-параметри у curl беріть у лапки, щоб оболонка не з'їла &.

200 application/json
ПолеТипОпис
itemsTranscription[]Сторінка транскрипцій, модель.
totalCountintegerЗагальна кількість з урахуванням фільтрів.
КодКолиЩо робити
400Невідоме значення status чи kind.Виправити фільтр.
Запитcurl
curl -sS "https://api.wavesift.com/v1/transcriptions?page=1&limit=20&status=completed&kind=upload&q=48213" \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKapplication/json
{
  "items": [
    { "id": "01a06f3e-…", "kind": "upload", "status": "completed", "title": "Дзвінок #48213, оператор Іванова",  }
  ],
  "totalCount": 1
}
Помилка400 Bad Requestapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "<причина: невідоме значення status або kind>"
}
DELETE/transcriptions/{id} Видалити транскрипцію
X-Api-Key

Видалити транскрипцію разом із сегментами, markdown і всіма її самарі. Незворотно.

Шлях
ПолеТипОпис
iduuidобов'язковеТранскрипція, яку видалити.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

Без тіла.

204 No Content

Порожня відповідь. Повторний виклик для того самого id дасть 404.

КодКолиЩо робити
403Чужа транскрипція.Перевірити id і ключ.
404Невідомий id.Перевірити id.
Запитcurl
curl -sS -X DELETE https://api.wavesift.com/v1/transcriptions/$ID \
  -H "X-Api-Key: $API_KEY"
Відповідь204 No Contentбез тіла
(порожня відповідь)
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
Розділ 6

Самарі

Пресет — це збережений промпт із назвою. Є п'ять глобальних пресетів сервера, серед них «Розбір дзвінка КЦ» для двоканальних розмов (тема звернення, результат, хід розмови з таймкодами, оцінка оператора за п'ятьма критеріями, ризики, наступні кроки), і власні пресети вашого акаунта. Самарі генерується за presetId, доступне лише для транскрипції зі статусом completed, асинхронне. Модель обирається планом акаунта і повертається в полі ollamaModel. Квоти на кількість самарі немає.

GET/summary-presets Доступні пресети
X-Api-Key

Увімкнені глобальні пресети плюс ваші власні.

Без параметрів.

Глобальні пресети id виду 0198c0de-0000-7000-8000-00000000000N
NНазва
…0001Повне самарі
…0002Ключові моменти
…0003Задачі та фікси
…0004Пояснення функціоналу
…0005Розбір дзвінка КЦ
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
200 application/json

{ items: SummaryPreset[] }. У глобальних isGlobal: true, їх не можна змінювати.

КодКолиЩо робити
401Ключ відсутній або недійсний.Перевірити ключ.
Запитcurl
curl -sS https://api.wavesift.com/v1/summary-presets \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKapplication/json
{
  "items": [
    { "id": "0198c0de-0000-7000-8000-000000000001", "name": "Повне самарі",         "prompt": "…", "isGlobal": true,  "isEnabled": true, "sortOrder": 1,  },
    { "id": "0198c0de-0000-7000-8000-000000000002", "name": "Ключові моменти",       "prompt": "…", "isGlobal": true,  "isEnabled": true, "sortOrder": 2,  },
    { "id": "0198c0de-0000-7000-8000-000000000003", "name": "Задачі та фікси",       "prompt": "…", "isGlobal": true,  "isEnabled": true, "sortOrder": 3,  },
    { "id": "0198c0de-0000-7000-8000-000000000004", "name": "Пояснення функціоналу", "prompt": "…", "isGlobal": true,  "isEnabled": true, "sortOrder": 4,  },
    { "id": "0198c0de-0000-7000-8000-000000000005", "name": "Розбір дзвінка КЦ",     "prompt": "…", "isGlobal": true,  "isEnabled": true, "sortOrder": 5,  },
    { "id": "01a06f5b-…",                           "name": "Оцінка розмови",    "prompt": "…", "isGlobal": false, "isEnabled": true, "sortOrder": 0,  }
  ]
}
Помилка401 Unauthorizedapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
  "title": "Unauthorized",
  "status": 401
}
POST/summary-presets Створити власний пресет
X-Api-Keyapplication/json

У промпті описуйте завдання й формат відповіді. Транскрипт вставляти не треба: сервер додає до промпту службовий вступ (пояснення формату таймкодів і міток мовців) і сам текст транскрипту. Якщо самарі потрібне не українською, скажіть про мову в промпті явно.

Тіло запиту application/json
ПолеТипОпис
namestringобов'язковеНазва пресету.
promptstringобов'язковеІнструкція для моделі без тексту транскрипту.
Редагування й видалення

PUT /summary-presets/{id} з тим самим тілом { "name", "prompt" }. DELETE /summary-presets/{id}204. Обидва працюють лише з власними пресетами, глобальні дають 403. Уже згенеровані самарі зберігають знімок назви й промпту, тому редагування пресету історію не змінює.

Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
Content-Typeapplication/jsonобов'язковий
200 application/json

Об'єкт SummaryPreset з isGlobal: false. Його id далі йде в presetId.

КодКолиЩо робити
400Порожні name або prompt.Заповнити поля.
409Досягнуто ліміт власних пресетів плану.Видалити непотрібний пресет.
Запитcurl
curl -sS https://api.wavesift.com/v1/summary-presets \
  -H "X-Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Оцінка розмови",
    "prompt": "Ти оцінюєш якість розмови. SPEAKER_1 — оператор, SPEAKER_2 — клієнт. Дай: 1) тему звернення одним реченням; 2) чи вирішено питання (так/ні/частково); 3) оцінку оператора 1–5 за ввічливість, точність, дотримання скрипту, з цитатами; 4) наступний крок. Відповідай українською, markdown."
  }'
Відповідь200 OKapplication/json
{
  "id": "01a06f5b-…",
  "name": "Оцінка розмови",
  "prompt": "Ти оцінюєш якість розмови…",
  "isGlobal": false,
  "isEnabled": true,
  "sortOrder": 0,
  "createdAt": "…",
  "updatedAt": "…"
}
Помилка409 Conflictapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
  "title": "Conflict",
  "status": 409,
  "detail": "<причина: ліміт власних пресетів плану>"
}
POST/transcriptions/{id}/summaries Замовити самарі
X-Api-Keyapplication/json

Поставити самарі в чергу. Відповідь одразу зі статусом queued; результат забирається окремим запитом за id самарі.

Шлях
ПолеТипОпис
iduuidобов'язковеТранскрипція зі статусом completed.
Тіло запиту application/json
ПолеТипОпис
presetIduuidобов'язковеГлобальний або власний пресет зі списку GET /summary-presets.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
Content-Typeapplication/jsonобов'язковий
200 application/json

Об'єкт Summary зі статусом queued. Його id це summaryId для наступних запитів.

КодКолиЩо робити
403Чужий або вимкнений пресет, чужа транскрипція.Перевірити presetId і id.
404Невідомий пресет або транскрипція.Перевірити ідентифікатори.
409Транскрипція ще не completed.Дочекатися статусу.
Запитcurl
curl -sS https://api.wavesift.com/v1/transcriptions/$ID/summaries \
  -H "X-Api-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"presetId":"01a06f5b-…"}'
Відповідь200 OKapplication/json
{
  "id": "01a06f7a-…",
  "transcriptionId": "01a06f3e-…",
  "presetId": "01a06f5b-…",
  "presetName": "Оцінка розмови",
  "ollamaModel": "gemma4:12b",
  "status": "queued",
  "markdown": null,
  "errorMessage": null,
  "createdAt": "2026-09-05T11:41:20.008Z",
  "completedAt": null
}
Помилка409 Conflictapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
  "title": "Conflict",
  "status": 409,
  "detail": "Transcription 01a06f3e-7c1a-7b52-9d2e-3f0c1a9d8e11 has no transcript yet (status: processing)"
}
GET/summaries/{summaryId} Статус і текст самарі
X-Api-Key

Опитуйте до status: "completed"; результат у полі markdown. Статуси ті самі: queuedprocessingcompleted | failed.

Шлях
ПолеТипОпис
summaryIduuidобов'язковеid з відповіді на замовлення самарі.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

Без тіла. Опитуйте раз на 5 секунд.

200 application/json

Об'єкт Summary. Після completed поле markdown містить готовий текст, при failed причина в errorMessage.

КодКолиЩо робити
403Самарі чужої транскрипції.Перевірити summaryId і ключ.
404Невідомий summaryId.Перевірити summaryId.
Запитcurl
curl -sS https://api.wavesift.com/v1/summaries/$SUMMARY_ID \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKcompleted
{
  "id": "01a06f7a-…",
  "transcriptionId": "01a06f3e-…",
  "presetId": "01a06f5b-…",
  "presetName": "Оцінка розмови",
  "ollamaModel": "gemma4:12b",
  "status": "completed",
  "markdown": "## Тема\nУточнення статусу замовлення №48213.\n\n## Вирішено\nТак.\n\n## Оцінка оператора\n- Ввічливість: 5 …",
  "errorMessage": null,
  "createdAt": "2026-09-05T11:41:20.008Z",
  "completedAt": "2026-09-05T11:42:03.551Z"
}
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
GET/summaries/{summaryId}/events Самарі потоком (SSE)
X-Api-Keytext/event-stream

Статус і токени по мірі генерації. Після перепідключення вже надіслані токени не повторюються, тому готовий текст беріть через GET /summaries/{summaryId}.

Шлях
ПолеТипОпис
summaryIduuidобов'язковеСамарі, за яким стежити.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий

У curl вимкніть буферизацію прапорцем -N.

200 text/event-stream
eventПоля dataОпис
statustype, status, messageЗнімок статусу самарі.
tokentype, tokenФрагмент тексту по мірі генерації.
КодКолиЩо робити
403Самарі чужої транскрипції.Перевірити summaryId і ключ.
404Невідомий summaryId.Перевірити summaryId.
Запитcurl
curl -sN https://api.wavesift.com/v1/summaries/$SUMMARY_ID/events \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKtext/event-stream
event: status
data: {"type":"status","status":"processing","token":null,"message":null,"stage":null,"percent":null}

event: token
data: {"type":"token","status":null,"token":"## Тема\n","message":null,"stage":null,"percent":null}

event: status
data: {"type":"status","status":"completed","token":null,"message":null,"stage":null,"percent":null}
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
GET/transcriptions/{id}/summaries Історія самарі транскрипції
X-Api-Key

Усі самарі однієї транскрипції, найновіші першими.

Шлях
ПолеТипОпис
iduuidобов'язковеТранскрипція.
Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
200 application/json

{ items: Summary[] }, найновіші першими.

КодКолиЩо робити
403Чужа транскрипція.Перевірити id і ключ.
404Невідомий id.Перевірити id.
Запитcurl
curl -sS https://api.wavesift.com/v1/transcriptions/$ID/summaries \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKapplication/json
{
  "items": [
    { "id": "01a06f7a-…", "presetName": "Оцінка розмови", "status": "completed", "markdown": "…",  }
  ]
}
Помилка404 Not Foundapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.5",
  "title": "Not Found",
  "status": 404
}
Розділ 7

Підписка

GET/subscription/current План, ліміти й використання
X-Api-Key

Поточний план, ліміти й використання за календарний місяць. У плані 0 означає «без ліміту», тоді відповідне поле …Remaining дорівнює null. Усі доступні плани: GET /subscription/plans.

Без параметрів.

Заголовки
ЗаголовокЗначення
X-Api-Keyatk_…обов'язковий
200 application/json

Об'єкт Subscription з вкладеним Plan. Приклад праворуч: акаунт на trial.

ПолеОпис
endsAtКінець trial. Після переходу на базовий план null.
audioMinutesUsed · audioMinutesRemainingХвилини за період і залишок; null, коли ліміту немає.
customPresetsCount · customPresetsRemainingВласні пресети і залишок.
КодКолиЩо робити
401Ключ відсутній або недійсний.Перевірити ключ.
Запитcurl
curl -sS https://api.wavesift.com/v1/subscription/current \
  -H "X-Api-Key: $API_KEY"
Відповідь200 OKapplication/json
{
  "subscriptionId": "01a06f12-…",
  "status": "active",
  "startsAt": "2026-09-05T11:30:02.114Z",
  "endsAt": "2026-09-19T11:30:02.114Z",
  "plan": {
    "id": "0198c0de-1000-7000-8000-000000000003",
    "code": "trial",
    "name": "Trial",
    "isEnabled": true,
    "isDefault": false,
    "priceMonthly": 0,
    "currency": "USD",
    "monthlyAudioMinutes": 0,
    "maxCustomPresets": 0,
    "maxUploadFileSizeMb": 0,
    "maxSeats": 1,
    "preferredSummaryModel": "gemma4:12b",
    "preferredWhisperModel": "large-v3-turbo",
    "sortOrder": 0,
    "isTrial": true,
    "trialDays": 14
  },
  "periodStart": "2026-09-01T00:00:00Z",
  "periodEnd": "2026-10-01T00:00:00Z",
  "audioMinutesUsed": 412.7,
  "audioMinutesRemaining": null,
  "transcriptionsCount": 96,
  "summariesCount": 88,
  "customPresetsCount": 1,
  "customPresetsRemaining": null
}
Помилка401 Unauthorizedapplication/problem+json
{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.2",
  "title": "Unauthorized",
  "status": 401
}
Довідка

Моделі даних

Усі об'єкти, які повертає API, з типами полів. uuid рядок UUID, datetime рядок ISO-8601 UTC, enum рядок із фіксованого набору. Позначка | null означає, що поле може бути порожнім.

Transcription

POST /transcriptions · GET /transcriptions/{id} · GET /transcriptions
ПолеТипОпис
iduuidІдентифікатор транскрипції, використовується в усіх дочірніх запитах.
kindenumupload для одного файлу, meeting коли передані mic_file і system_file.
statusenumqueued | processing | completed | failed.
titlestring | nullНазва з поля title, у пакеті дорівнює імені файлу.
languagestringЗапитана мова: ISO-код або auto.
detectedLanguagestring | nullВизначена мова, заповнюється після completed.
whisperModelstring | nullМодель розпізнавання, якою оброблено запис, наприклад large-v3-turbo.
durationSecondsnumber | nullТривалість запису в секундах, після completed. За нею списуються хвилини плану.
hasMicTrackbooleanЧи передано mic_file.
hasSystemTrackbooleanЧи передано system_file.
micFileSizeBytesinteger | nullРозмір mic_file у байтах.
systemFileSizeBytesinteger | nullРозмір system_file у байтах.
progressStagestring | nullРядок поточної стадії для відображення, наприклад TRANSCRIBE_START, DONE.
progressPercentinteger | nullПрогрес 0–100 під час processing.
errorMessagestring | nullПричина при failed.
startedAtdatetime | nullКоли агент узяв запис у роботу.
completedAtdatetime | nullКоли транскрипція завершена.
audioDeletedAtdatetime | nullКоли видалено оригінальне аудіо. Для одного потоку також означає, що діаризація за голосом завершена.
createdAtdatetimeМомент завантаження.

Segment

GET /transcriptions/{id}/segments
ПолеТипОпис
iduuidІдентифікатор сегмента.
startnumberПочаток у секундах від початку запису.
endnumberКінець у секундах.
textstringРозпізнаний текст сегмента.
sourceenumyou — трек mic_file; other — трек system_file.
speakerUserIduuid | nullДля серверних інтеграцій завжди null.
speakerLabelstring | nullSPEAKER_1, SPEAKER_2, … Стерео: 1 = лівий канал, 2 = правий. Один потік: null до завершення діаризації.

Summary

POST /transcriptions/{id}/summaries · GET /summaries/{summaryId}
ПолеТипОпис
iduuidІдентифікатор самарі (summaryId).
transcriptionIduuidТранскрипція, для якої згенеровано самарі.
presetIduuidПресет, за яким замовлено самарі.
presetNamestringЗнімок назви пресету на момент замовлення.
ollamaModelstringМодель, обрана планом акаунта, наприклад gemma4:12b.
statusenumqueued | processing | completed | failed.
markdownstring | nullГотовий текст самарі після completed.
errorMessagestring | nullПричина при failed.
createdAtdatetimeМомент замовлення.
completedAtdatetime | nullМомент завершення.

SummaryPreset

GET /summary-presets · POST /summary-presets
ПолеТипОпис
iduuidІдентифікатор для presetId.
namestringНазва пресету.
promptstringІнструкція для моделі.
isGlobalbooleantrue для пресетів сервера, їх не можна змінювати.
isEnabledbooleanЧи доступний для генерації.
sortOrderintegerПорядок відображення.
createdAt · updatedAtdatetimeСтворення й остання зміна.

ApiKey

POST /user/api-keys · GET /user/api-keys · DELETE /user/api-keys/{id}
ПолеТипОпис
iduuidІдентифікатор ключа для відкликання.
ownerUserIduuidАкаунт-власник.
ownerEmailstringEmail власника.
partnerNamestringНазва з поля name при створенні.
keyPrefixstringПерші символи ключа для впізнавання, наприклад atk_4b0zgyEB.
bypassLimitsbooleanСлужбовий прапорець обходу лімітів плану.
isActivebooleanfalse після відкликання.
expiresAtdatetime | nullТермін дії, null для безстрокового.
revokedAtdatetime | nullМомент відкликання.
lastUsedAtdatetime | nullОстанній запит із цим ключем.
createdAtdatetimeМомент створення.

User

POST /auth/register · POST /auth/login · GET /user/me
ПолеТипОпис
iduuidІдентифікатор акаунта.
emailstringЛогін.
usernamestring | nullВідображуване ім'я.
roleenumДля інтеграцій client.
statusenumСтан акаунта, робочий стан active.
createdAt · updatedAtdatetimeСтворення й остання зміна.

Subscription

GET /subscription/current
ПолеТипОпис
subscriptionIduuidІдентифікатор підписки.
statusenumСтан підписки, робочий стан active.
startsAtdatetimeПочаток підписки.
endsAtdatetime | nullКінець trial. Після переходу на базовий план null.
planPlanОб'єкт плану, нижче.
periodStart · periodEnddatetimeКалендарний місяць, за який рахується використання.
audioMinutesUsednumberХвилини аудіо за період.
audioMinutesRemainingnumber | nullЗалишок; null, коли ліміту немає.
transcriptionsCountintegerТранскрипцій за період.
summariesCountintegerСамарі за період.
customPresetsCountintegerВласних пресетів.
customPresetsRemaininginteger | nullЗалишок; null, коли ліміту немає.

Plan

поле plan · GET /subscription/plans
ПолеТипОпис
iduuidІдентифікатор плану.
code · namestringКод і назва, наприклад trial / Trial.
isEnabled · isDefaultbooleanЧи активний план і чи він базовий після trial.
priceMonthly · currencynumber · stringЦіна за місяць і валюта.
monthlyAudioMinutesintegerХвилин аудіо на місяць, 0 означає без ліміту.
maxCustomPresetsintegerВласних пресетів, 0 без ліміту.
maxUploadFileSizeMbintegerМаксимальний файл у МБ, 0 без ліміту.
maxSeatsintegerКількість місць.
preferredSummaryModelstringМодель самарі плану, наприклад gemma4:12b.
preferredWhisperModelstringМодель розпізнавання плану, наприклад large-v3-turbo.
isTrial · trialDaysboolean · integerОзнака trial і його тривалість у днях.
sortOrderintegerПорядок відображення.

Problem

усі помилки · application/problem+json · RFC 7807
ПолеТипОпис
typestringПосилання на опис статусу в RFC 9110.
titlestringНазва статусу, наприклад Conflict.
statusintegerHTTP-код.
detailstring | nullПричина людською мовою, коли сервер її знає.
Довідка

Коди помилок

Помилки повертаються як application/problem+json (RFC 7807). Кожна відповідь несе заголовок X-Correlation-Id; можете передавати свій UUID у цьому ж заголовку, він повернеться незмінним. Вказуйте його у зверненнях до нас.

КодКолиЩо робити
400Невалідне тіло або параметри: немає файлу, непідтримуване розширення, невідомий status/kind, поганий JSON.Виправити запит.
401Немає X-Api-Key, ключ невірний, відкликаний або прострочений; для Bearer токен протух (15 хв).Перевірити ключ або створити новий; для Bearer увійти знову. Не повторювати в циклі.
403Ресурс належить іншому акаунту; керування ключами через API-ключ; глобальний або чужий пресет.Перевірити id і спосіб автентифікації.
404Немає такої транскрипції / самарі / пресету / ключа, або транскрипт ще не готовий (для /markdown).Перевірити id чи дочекатися completed.
409Порушення правила: самарі для незавершеної транскрипції, ліміт плану на розмір файлу, хвилини чи кількість пресетів, 5 активних ключів.Дочекатися статусу або перевірити ліміти.
410Оригінальне аудіо вже видалене (тільки для /audio/{track}).Транскрипт і самарі доступні далі.
413Тіло більше 6 ГБ. Відповідь може прийти від проксі з HTML-тілом.Розбити або стиснути (FLAC).
5xxЗбій на нашому боці.Повторити з паузою, надіслати нам X-Correlation-Id.
Довідка

Ліміти й зберігання

ПравилоЩо означає
Trial 14 днівДля кожного нового акаунта: квоти тарифу не діють (розмір файлу, хвилини, кількість власних пресетів), лишається лише технічний ліміт 6 ГБ на запит. Дата закінчення в endsAt; після неї акаунт переходить на базовий план, endsAt стає null.
Хвилини аудіоСписуються за тривалістю запису після завершення транскрипції. Завантаження понад ліміт дає 409 або окремий error у пакетній відповіді.
Аудіо не зберігаєтьсяДля стерео-запису з розділенням по каналах оригінальний файл видаляється одразу після завершення транскрипції, для одного потоку після діаризації за голосом; у будь-якому разі не пізніше ніж за 7 днів. Момент видалення видно в audioDeletedAt. Тримайте свою копію.
Транскрипти й самаріЗберігаються без обмеження терміну, доки ви їх не видалите через DELETE /transcriptions/{id}.
Ліміт тіла6 ГБ на запит незалежно від плану.
КлючіДо 5 активних одночасно; термін дії за бажанням.
Довідка

Повний сценарій одним скриптом

Файл run-call.sh: bash + curl + jq. Завантаження стерео-запису, очікування, транскрипт, самарі за пресетом «Розбір дзвінка КЦ». Ключ береться зі змінної середовища WAVESIFT_API_KEY. Це цілий файл, а не набір команд для вставки по одній.

Файлrun-call.sh · bash
#!/usr/bin/env bash
set -euo pipefail
API=https://api.wavesift.com/v1
FILE=${1:?шлях до стерео wav}
PRESET_ID=${2:-0198c0de-0000-7000-8000-000000000005}

AUTH="X-Api-Key: ${WAVESIFT_API_KEY:?задай WAVESIFT_API_KEY}"

ID=$(curl -sS "$API/transcriptions" -H "$AUTH" -F "system_file=@$FILE" -F "language=uk" \
  -F "title=$(basename "$FILE")" | jq -r .id)
echo "transcription: $ID"

while :; do
  S=$(curl -sS "$API/transcriptions/$ID" -H "$AUTH")
  STATUS=$(jq -r .status <<<"$S")
  echo "  $STATUS $(jq -r '.progressStage // ""' <<<"$S") $(jq -r '.progressPercent // ""' <<<"$S")"
  [[ $STATUS == completed ]] && break
  [[ $STATUS == failed ]] && { jq -r .errorMessage <<<"$S"; exit 1; }
  sleep 10
done

curl -sS "$API/transcriptions/$ID/markdown" -H "$AUTH" -o "$ID.transcript.md"

SUMMARY_ID=$(curl -sS "$API/transcriptions/$ID/summaries" -H "$AUTH" \
  -H "Content-Type: application/json" -d "{\"presetId\":\"$PRESET_ID\"}" | jq -r .id)

while :; do
  S=$(curl -sS "$API/summaries/$SUMMARY_ID" -H "$AUTH")
  STATUS=$(jq -r .status <<<"$S")
  [[ $STATUS == completed ]] && { jq -r .markdown <<<"$S" > "$ID.summary.md"; break; }
  [[ $STATUS == failed ]] && { jq -r .errorMessage <<<"$S"; exit 1; }
  sleep 5
done
echo "done: $ID.transcript.md, $ID.summary.md"
Скопійовано