Lyrics / Subtitle Sync API
The Lyrics / Subtitle Sync API turns a public audio URL into lyrics plus line-level subtitle artifacts through OmnAPI’s managed transcription and timing pipeline. It is designed for MV captions, lyric preview, and any workflow that needs SRT/VTT/LRC/JSON timing from ordinary audio.
Use this flow:
POST /api/v1/subtitles/quoteto estimate credits and public price.POST /api/v1/subtitleswith anIdempotency-Key.- Poll
GET /api/v1/subtitles/{taskId}. - Read
artifacts.srtUrl,artifacts.vttUrl,artifacts.lrcUrl, orartifacts.jsonUrlfrom the completed task.
source.durationSec is optional. If omitted, OmnAPI safely probes the public
audio URL before quote/create and uses the server-detected duration for pricing,
budget checks, and queue sizing. Send it only as a client hint when you already
know the duration.
curl -X POST https://api.omnapi.com/api/v1/subtitles/quote \ -H "x-api-key: $OMNAPI_KEY" \ -H "Content-Type: application/json" \ -d '{ "source": { "type": "audio", "audioUrl": "https://example.com/song.mp3" }, "budget": { "maxCostUsdPerMin": 0.05 } }'Response:
{ "credits": 1, "durationSec": 60, "estimatedUsd": 0.02, "maxCostUsdPerMin": 0.05, "publicUsdPerMin": 0.02}budget.maxCostUsdPerMin is a public price guard. Quote returns both the active
price and submitted ceiling so clients can decide before creating a task. Create
fails with SUBTITLE_BUDGET_EXCEEDED before credits are deducted when the
active subtitle price is above the submitted ceiling.
Quote accepts the same request envelope as create, including mode,
language, outputs, maxCredits, and config, although only source and
budget fields affect the current estimate.
Create
Section titled “Create”curl -X POST https://api.omnapi.com/api/v1/subtitles \ -H "x-api-key: $OMNAPI_KEY" \ -H "Idempotency-Key: subtitle-demo-001" \ -H "Content-Type: application/json" \ -d '{ "mode": "extract", "source": { "type": "audio", "audioUrl": "https://example.com/song.mp3" }, "language": "auto", "outputs": ["srt", "json", "vtt", "lrc"], "budget": { "maxCostUsdPerMin": 0.05 }, "config": { "metadata": { "purpose": "mv-caption" } } }'Response:
{ "taskId": "task_01J...", "status": "PENDING", "creditsRequired": 1, "pollUrl": "/api/v1/subtitles/task_01J..."}| Field | Type | Required | Notes |
|---|---|---|---|
mode | "extract" | — | Default extract. |
source.type | "audio" | yes | Public audio URL input. |
source.audioUrl | URI string | yes | Public http(s) URL. Private/local network URLs are rejected. |
source.durationSec | number | — | Optional 1-600 second hint. If omitted, OmnAPI probes the audio before quoting or creating. |
language | string | — | 2-16 chars. Omit or use "auto" for automatic language handling. |
outputs | array | — | 1-4 entries from srt, json, vtt, lrc; default is srt + json. |
budget.maxCostUsdPerMin | number | — | Public price ceiling from 0.001 to 1 USD/min. Use 0.05 to enforce a five-cent/minute cap. |
maxCredits | number | — | Optional create-time credit spend guard, minimum 1. |
config | object | — | Standard task config: priority, tags, metadata, webhookUrl. |
curl https://api.omnapi.com/api/v1/subtitles/task_01J... \ -H "x-api-key: $OMNAPI_KEY"Completed response:
{ "taskId": "task_01J...", "status": "COMPLETED", "progress": 100, "lyrics": "First lyric line\nSecond lyric line", "timeline": { "lines": [ { "text": "First lyric line", "startSec": 0.12, "endSec": 3.4, "section": "Verse 1" } ], "words": [] }, "artifacts": { "srt": { "url": "https://cdn.omnapi.com/...", "expiresAt": "2026-07-12T00:00:00.000Z", "retentionDays": 7 }, "json": { "url": "https://cdn.omnapi.com/...", "expiresAt": "2026-07-12T00:00:00.000Z", "retentionDays": 7 }, "srtUrl": "https://cdn.omnapi.com/...", "jsonUrl": "https://cdn.omnapi.com/..." }, "warnings": []}Current extraction returns line-level timing. timeline.words is included for a
stable response shape and may be empty.
MV Auto Subtitles
Section titled “MV Auto Subtitles”MV Fast and Studio use the same Subtitle Sync capability when a request enables
subtitles but does not provide srtUrl.
{ "mode": "fast", "source": { "type": "audio", "audioUrl": "https://example.com/song.mp3" }, "subtitles": true, "subtitle": { "mode": "auto", "language": "auto", "maxCostUsdPerMin": 0.05, "fallback": "continue_without_subtitles" }}Use subtitle.mode="provided" when your product requires caller-supplied timing
only. Use subtitle.mode="off" to disable subtitles even if a legacy
subtitles toggle is present.
Error Codes
Section titled “Error Codes”| Code | HTTP | Meaning |
|---|---|---|
SUBTITLE_BUDGET_EXCEEDED | 400 | Active public subtitle price is above budget.maxCostUsdPerMin. |
AUDIO_DURATION_INVALID | 400 | source.durationSec is outside the subtitle extraction range or does not match the probed duration. |
AUDIO_DURATION_PROBE_FAILED | 400 | OmnAPI could not determine duration from the submitted audio. |
AUDIO_FILE_TOO_LARGE | 413 | Submitted audio exceeds the Subtitle Sync audio size limit. |
AUDIO_URL_INVALID | 400 | The audio URL is invalid, private/local, or otherwise not allowed. |
AUDIO_URL_UNREACHABLE | 400 / 408 / 502 | OmnAPI could not fetch or inspect the audio URL. |
SERVICE_UNAVAILABLE | 503 | Subtitle Sync is disabled, temporarily unavailable, or all extraction slots are busy. |
SUBTITLE_FILE_INVALID | 400 | A supplied subtitle file could not be parsed into usable cues. |
SUBTITLE_GENERATION_FAILED | 400 / 502 | Audio download, transcription, or subtitle artifact generation failed. |
SUBTITLE_NO_SPEECH_DETECTED | 422 | The audio did not produce usable lyric or speech content. |