review=true, it stops for a human before delivery. A job.awaiting_review event carries a review_url; job.complete follows once someone approves.
review_stage decides where it stops. See POST /transcribe for the parameter itself.
What “awaiting review” does and does not hold back
Thejob.complete webhook is held until approval. Nothing else is.
GET /api/v1/jobs/{id} reports the job’s real pipeline state throughout, and once a stage has produced output that output is readable — so an aligned-stage job returns status: "complete" with download URLs before anyone has approved. Approval is recorded in review_approved_at.
Review URL
job.awaiting_review webhook, and is also returned by GET /api/v1/jobs/{id} and GET /api/v1/jobs under review_url. A webhook endpoint is not required — a polling consumer can run the whole flow.
review_url is null until the job reaches its gate and a token is minted — after transcription for review_stage: "transcript", after alignment for "aligned". Poll until it is non-null rather than caching a null.
A job submitted with review_delivery: "api" mints no token at all, so its
review_url stays null permanently and our review page cannot be opened for it.
That is deliberate: the link’s security is the token.
The token is valid for 7 days and may be used more than once — a reviewer can open the link, leave, and come back. It cannot be used after review_expires_at; contact support@lyrcs.ai for a new one.
Two ways to approve
Both converge on the same approval and the same outputs; nothing downstream
distinguishes them, and the first approval wins whichever door it came through.
review_delivery at submission decides which doors a job opens — see
Running Review In Your Own Product.
Approving
The reviewer approves in the browser atreview_url. Corrections made there are saved with the approval.
Corrections are re-aligned. On an aligned-stage job, editing a line invalidates the word-level timings that were derived from the old text, so approval re-runs alignment over the corrected lines. Where re-alignment is unavailable for your organisation, the word-level track is removed rather than returned describing text that is no longer there; the line-level LRC and SRT are unaffected. The approval response reports which happened:
Webhook payloads
job.awaiting_review — fires when the job reaches its gate:review_stage tells you which gate fired — the same event name is used at both, and what the reviewer is being asked to check differs between them.
job.complete — fires after approval, carrying the same fields as a non-review job:
word_align=true and the timings survived review.
Review fields on the job response
review_approved_at is null until approval, then an ISO timestamp. It is the only field that tells you a human has signed off.
Known limitations
- The
job.completewebhook fired after approval is single-attempt — it does not retry, unlike the standard flow which retries at +1 min, +5 min and +30 min. If you miss it, pollGET /jobs/{id};review_approved_atwill be set and the results are available. - A
review_stage: "transcript"job waits up to 8 days. If nobody approves, it is markedfailedwith stagereviewrather than remainingprocessingindefinitely. - Adding or removing lines requires that the timings can be re-derived. At the aligned gate for an organisation without re-alignment, only the wording of existing lines can change; an attempt to alter the line count is refused with
409 REV_001.