review_stage, and the choice changes what they can affect.
There are two ways to reach that human, and they are two doors into the same held
job rather than two modes: the artist reviews on our page via review_url
(this guide), or inside your product via
POST /jobs/{id}/approve. Both converge on the same
approval, and you can choose per job with review_delivery. If the artist is
already signed in to your app, read
Running Review In Your Own Product instead.
Choosing a stage
review_stage: "transcript" — the job stops as soon as the lyrics exist, before any timing work. The reviewer checks words; alignment then runs on the text they approved.
Use this when corrections should reach the aligner. It is the right default for distributor workflows where an artist confirms wording.
review_stage: "aligned" (the default) — the job aligns first and stops with finished, time-synced lines. The reviewer can hear each line in place.
Use this for QC on timing. Corrections are still accepted, and are re-timed against the audio on approval.
"aligned" is the default so that integrations built before review_stage
existed are unaffected.End-to-end: review before alignment
1
Submit with review_stage=transcript
202 { "job_id": "...", "status": "queued", "review_required": true, "review_stage": "transcript" }.webhook_url is optional — see Without webhooks below.2
Transcription runs (~60 seconds)
Lyrics, transliteration and translation are produced. No alignment yet.
3
job.awaiting_review fires
4
Route review_url to the artist
Forward it by email, SMS, or your own platform. The artist does not need a
lyrcs.ai account.
5
The artist reviews and approves
They see the lyrics without timestamps — timings do not exist yet — and can
correct any line before approving.
6
Alignment runs on the approved text (~30 seconds)
This is the point of the transcript gate: the aligner receives the corrected
words, not the original ones.
7
job.complete fires with full results
Transcript, transliteration, translation and download URLs for LRC, SRT and —
when requested — word-level JSON.
End-to-end: review after alignment
Identical, with two differences: the gate fires after alignment (~90s rather than ~60s), the reviewer sees time-synced lines and can click any timestamp to hear it, and approval finalises the job rather than starting alignment. If they correct a line, approval re-runs alignment over the corrected text so the word-level timings continue to describe the words actually present. Where re-alignment is unavailable for your organisation, the word-level track is removed instead of being returned stale — the approval response says which happened via itsalignment field.
What is held back, precisely
Only thejob.complete webhook waits for approval.
GET /api/v1/jobs/{id} reports the pipeline’s real state throughout, and output that exists is readable. On an aligned-stage job that means status: "complete" and working download URLs before anyone has approved.
Without webhooks
A webhook endpoint is convenient but not required. Every field the flow needs is on the job:review_url is non-null to get the link, then until review_approved_at is non-null to learn approval happened. A transcript-stage job also reports stage: "awaiting_review" while it waits, so you can find everything pending in one sweep. At scale, poll GET /jobs with updated_since rather than each job individually.
review_url is null until the job reaches its gate — after transcription for the transcript stage, after alignment for the aligned stage. Do not cache a null value.
Tokens and expiry
Review tokens are valid for 7 days and may be used more than once, so a reviewer can open the link, leave, and return. Afterreview_expires_at the link stops working; contact support@lyrcs.ai for a new one.
A review_stage: "transcript" job that is never approved is marked failed with stage review after 8 days, rather than sitting in processing forever.
Review in batch jobs
Batch jobs support both parameters per job:review_url appears in GET /api/v1/batch/{id} once that job reaches its gate.
What a reviewer can change
They can retype any line, and — where the timings can be produced afresh — add, delete and reorder lines. That matters because transcription gets line boundaries wrong as well as words: a line can be missed entirely, two sung lines merged into one, or one split across two. Adding and removing lines is offered when the job is held at the transcript gate, where alignment has not run yet, and at the aligned gate only where re-alignment is available. Where it is not, the wording of existing lines can still be corrected — but a new line could only be given a timestamp nobody measured, so the control is not offered and an attempt is refused with409 REV_001.
Line operations apply to both scripts together. Transliteration is position-mapped to the original, so inserting into one alone would misalign every pair below it.
Heavy edits are recorded
Every approval records how many lines changed on each script, and keeps a write-once snapshot of what the model originally produced. An edit that changes most of the lyric is additionally flagged as a replacement. Nothing is blocked. A genuinely poor transcript deserves a heavy correction, and refusing one would punish a reviewer for our error. The flag exists so that wholesale replacement is visible rather than invisible.Other limitations
- The
job.completewebhook fired after approval is single-attempt and does not retry. If you miss it, poll the job.