webhook_url when submitting a job or batch — lyrcs.ai will POST the event payload to that URL.
Events
Retry schedule
lyrcs.ai retries failed webhook deliveries (non-2xx or timeout) on this schedule:
Your endpoint must return a
2xx response within 10 seconds or the delivery is counted as failed.
The
job.complete webhook fired after artist approval in the review flow uses single-attempt delivery — it does not retry. Ensure your review webhook endpoint is reliable.Delivery headers
Every delivery carries these:Signature verification
Every webhook delivery includes anX-Lyrcs-Signature header containing an
HMAC-SHA256 signature of the raw request body, keyed with your webhook_secret.
The header value is prefixed, in the form sha256=<hex digest>. Strip the
prefix before comparing — passing the whole header to a hex decoder yields a
buffer of the wrong length, and timingSafeEqual throws rather than returning
false.
Verify the signature before processing the payload to confirm the request came
from lyrcs.ai.
Node.js — signature verification
Event payloads
job.complete
Fires when a job completes successfully.downloads is omitted when align=false was set. cultural_notes may be null. end_user is present only when the job was submitted with one.
Authorization header to fetch.
words_original and words_transliterated are present when word_align_requested: true (the default). Jobs submitted with word_align=false include only lrc_* and srt_* in downloads.job.awaiting_review
Fires instead ofjob.complete when review=true and the job reaches its review gate. No results block — the job.complete webhook is what waits for approval.
The gate is after transcription when review_stage is "transcript", and after alignment when it is "aligned" (the default). The payload’s review_stage field says which, since the same event fires at both.
Note that only this webhook is deferred: GET /jobs/{id} continues to report the job’s real state, and on an aligned-stage job the results are readable before approval. review_approved_at is the field that means a human signed off.
review_url and expires_at are null when the job was submitted with
review_delivery: "api" — no review link is created for those jobs by design.
Approve them at approve_url; see
Running Review In Your Own Product.
review_url to the artist. When they approve, job.complete fires with the full payload.
artist_url is a durable, catalogue-wide link for a submission that carried an
end_user — it opens that artist’s own page (their
songs, review, downloads, and video ordering) and slides its own expiry, so it
keeps working for weeks. It is null when the job had no end_user. See
Running Review In Your Own Product.
job.degraded
Fires on the first Gemini 503 retry only. The job is still processing — this is informational. Do not assume the job has failed.job.failed
Fires when a job fails permanently after all retries are exhausted.batch.complete
Fires when all jobs in a batch have finished — whether complete or failed.status is "complete" if all jobs succeeded, "partial" if any failed or timed out.
downloads is included per job only when status === "complete" AND align_requested === true for that job.