{"openapi":"3.1.0","info":{"title":"lyricbook API","version":"1","summary":"Lyrics for a song, found online or written down from its recording.","description":"Send Spotify or YouTube links, or audio files, and get their lyrics as JSON, LRC, SRT, text or Markdown. Jobs are billed from your account's credits at the same prices as the site. Guide: https://lyricbook.ai/docs/api","contact":{"email":"support@lyricbook.ai"},"termsOfService":"https://lyricbook.ai/terms"},"servers":[{"url":"https://lyricbook.ai/api/v1"}],"security":[{"apiKey":[]}],"externalDocs":{"url":"https://lyricbook.ai/docs/api"},"paths":{"/jobs":{"post":{"operationId":"createJobs","summary":"Make lyric jobs from links and uploads","description":"Charges the account's credits for every new song at once, or for none. Spotify albums become one job per song. Every song is transcribed from its recording and timed by word and by line. With `published_lyrics`, nothing is transcribed or charged: Spotify songs whose lyrics are published come back completed, and the rest are skipped.","parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string","maxLength":255},"description":"Retrying with the same key returns the jobs already made instead of charging again."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobsRequest"}}}},"responses":{"202":{"description":"The jobs, made or found under the Idempotency-Key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobsResponse"}}}},"400":{"description":"The request isn't valid (see `error.code`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, or one that isn't valid or was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Not enough credits: `error.required` and `error.available` say how many.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No songs at that link, or an unknown `upload_id`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Every upload was already used by another job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"An upload is no longer stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"An upload's length couldn't be read: send `duration_ms`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limited, or over the account's limits on songs in progress (`in_flight_limit`) or songs a day (`daily_limit`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"A link couldn't be looked up, or the transcription service didn't respond. Nothing was charged.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"504":{"description":"Looking the songs up took too long. Nothing was charged; send it again.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"operationId":"listJobs","summary":"List the account's jobs, newest first","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"`next_cursor` of the previous page."},{"name":"status","in":"query","schema":{"enum":["queued","processing","completed","failed"]}}],"responses":{"200":{"description":"One page of jobs.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobList"}}}},"400":{"description":"A bad `limit`, `cursor` or `status`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, or one that isn't valid or was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests. `Retry-After` says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/{id}":{"get":{"operationId":"getJob","summary":"Get a job","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The job.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Job"}}}},"401":{"description":"No API key, or one that isn't valid or was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such job on this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests. `Retry-After` says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/jobs/{id}/lyrics":{"get":{"operationId":"getLyrics","summary":"Download a completed job's lyrics","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"format","in":"query","schema":{"enum":["json","lrc","srt","txt","md"],"default":"json"}},{"name":"view","in":"query","schema":{"enum":["original","translation","both"],"default":"original"},"description":"What the text formats hold. JSON always carries the original and the translation."},{"name":"timing","in":"query","schema":{"enum":["line","word"],"default":"line"},"description":"`word`: LRC marks every word of the original lines (Enhanced LRC); needs a sheet timed by word (`word_timing`), as every transcribed sheet is. JSON always carries the words it has."}],"responses":{"200":{"description":"The lyrics in the asked format.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LyricSheet"}},"text/plain":{"schema":{"type":"string"}},"application/x-subrip":{"schema":{"type":"string"}},"text/markdown":{"schema":{"type":"string"}}}},"400":{"description":"A bad `format`, `view` or `timing`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, or one that isn't valid or was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such job on this account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The job is still queued or processing (`not_ready`), or it failed (`job_failed`).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The lyrics were deleted, 24 hours after the job was made.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"LRC and SRT need timings the sheet doesn't have, there is no translation for that view, or `timing=word` on a sheet without word timing.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests. `Retry-After` says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quote":{"get":{"operationId":"quote","summary":"What a link is and what it costs","description":"The price to transcribe, as POST /jobs charges it, translation included. Published lyrics and the free song can only lower it.","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","format":"uri"}},{"name":"translate_to","in":"query","schema":{"enum":["ar","bn","yue","zh","zh-Hant","cs","da","nl","en","fi","fr","de","el","he","hi","hu","id","it","ja","ko","ms","no","fa","pl","pt","ro","ru","es","sw","sv","tl","ta","th","tr","uk","ur","vi"]},"description":"Price the songs translated into this language, as POST /jobs would. Leave it out for no translation."},{"name":"chords","in":"query","schema":{"enum":["true","false"],"default":"false"},"description":"Price the songs with their chords, as POST /jobs would with `chords`."}],"responses":{"200":{"description":"The link's songs and their price.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Quote"}}}},"400":{"description":"Not a Spotify song or album link, or a YouTube video link, or an unknown `translate_to`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, or one that isn't valid or was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Nothing at that link.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests. `Retry-After` says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/account":{"get":{"operationId":"getAccount","summary":"The account's credits and limits","responses":{"200":{"description":"The account.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"description":"No API key, or one that isn't valid or was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many requests. `Retry-After` says how many seconds to wait.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/uploads":{"post":{"operationId":"createUpload","summary":"Get a URL to upload an audio file to","description":"PUT the file to `upload.url` with exactly `upload.headers` within 2 hours, then make a job with its `upload_id`. Files a job doesn't use are deleted after about 3 hours.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadRequest"}}}},"responses":{"201":{"description":"Where to send the file.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Upload"}}}},"400":{"description":"Not an audio file, or over the size limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"No API key, or one that isn't valid or was revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many uploads; too many files no job has used yet (`upload_quota`); earlier uploads from this account not stored yet (`uploads_in_flight`); or the service is busy (`uploads_busy`). Retry the last two after `Retry-After` seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{"job.completed":{"post":{"summary":"job.completed","description":"A job made through the API completed. Fetch its lyrics from `data.links.lyrics`.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobEvent"}}}},"responses":{"200":{"description":"Any 2xx answer counts as delivered; anything else is retried."}}}},"job.failed":{"post":{"summary":"job.failed","description":"A job made through the API failed. Its credits are refunded automatically.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobEvent"}}}},"responses":{"200":{"description":"Any 2xx answer counts as delivered; anything else is retried."}}}},"job.refunded":{"post":{"summary":"job.refunded","description":"A failed job's credits, or its free song, went back to the account.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobEvent"}}}},"responses":{"200":{"description":"Any 2xx answer counts as delivered; anything else is retried."}}}},"webhook.test":{"post":{"summary":"webhook.test","description":"Sent by \"Send test event\" on the API page. Tried once.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestEvent"}}}},"responses":{"200":{"description":"Any 2xx answer counts as delivered; anything else is retried."}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"An API key from the API page of your account: `lyr_live_…`."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}},"additionalProperties":true}}},"Job":{"type":"object","required":["id","object","status","stage","input","title","artist","duration_ms","artwork_url","lyrics_source","options","credits_charged","free_song","refunded","error","metadata","created_via","created_at","finished_at","results_expire_at","results_deleted","links"],"properties":{"id":{"type":"string","format":"uuid"},"object":{"const":"job"},"status":{"enum":["queued","processing","completed","failed"]},"stage":{"type":["string","null"],"enum":["downloading","separating","transcribing","translating",null],"description":"What a processing job is doing; null otherwise."},"input":{"type":"object","required":["type","url"],"properties":{"type":{"enum":["spotify","youtube","upload"]},"url":{"type":["string","null"],"format":"uri","description":"The song or video; null for an upload."}}},"title":{"type":["string","null"]},"artist":{"type":["string","null"]},"duration_ms":{"type":["integer","null"],"description":"The length the job was priced on."},"artwork_url":{"type":["string","null"],"format":"uri"},"lyrics_source":{"enum":["transcribed","lrclib","lyrics.ovh",null],"description":"Where the words came from. `transcribed`: written down from the recording. `lrclib` or `lyrics.ovh`: published lyrics from LRCLIB (lrclib.net) or found through lyrics.ovh; credit the source wherever you show them. Null until known, and for published lyrics once they are deleted."},"options":{"type":"object","required":["chords","source_language","translate_to"],"properties":{"chords":{"type":"boolean"},"source_language":{"type":"string","description":"This song's: its item's, else the request's."},"translate_to":{"type":["string","null"]}}},"credits_charged":{"type":"number","description":"Credits this job used, after any settlement on the decoded length. Refunded when the job fails."},"free_song":{"type":"boolean","description":"The account's free song paid for this job."},"refunded":{"type":"boolean","description":"The job failed and its credits (or free song) went back."},"error":{"oneOf":[{"type":"null"},{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}}],"description":"Why a failed job failed; null otherwise."},"metadata":{"type":["object","null"],"description":"The `metadata` sent with the job, as it was sent."},"created_via":{"enum":["api","web"]},"created_at":{"type":"string","format":"date-time"},"finished_at":{"type":["string","null"],"format":"date-time","description":"When it completed or failed."},"results_expire_at":{"type":"string","format":"date-time","description":"Lyrics are deleted at this time, 24 hours after the job was made."},"results_deleted":{"type":"boolean"},"links":{"type":"object","required":["self","lyrics","web"],"properties":{"self":{"type":"string","format":"uri"},"lyrics":{"type":"string","format":"uri"},"web":{"type":"string","format":"uri","description":"The lyrics page on the site (signed in as the account)."}}}}},"JobList":{"type":"object","required":["data","has_more","next_cursor"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"]}}},"CreateJobsRequest":{"type":"object","required":["items"],"additionalProperties":false,"properties":{"items":{"type":"array","minItems":1,"maxItems":50,"description":"Up to 50 items, and 50 songs once albums are expanded.","items":{"oneOf":[{"type":"string","description":"A Spotify song or album link, or a YouTube video link."},{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":"string"},"source_language":{"enum":["auto","ar","bn","yue","zh","cs","da","nl","en","fi","fr","de","el","he","hi","hu","id","it","ja","ko","ms","no","fa","pl","pt","ro","ru","es","sw","sv","tl","ta","th","tr","uk","ur","vi",null],"description":"The language this item is sung in, over the request's `source_language`. An album's applies to every song on it."}}},{"type":"object","required":["upload_id"],"additionalProperties":false,"properties":{"upload_id":{"type":"string","pattern":"^upl_[0-9a-f]{32}$"},"duration_ms":{"type":"integer","minimum":1,"description":"The file's length. Without it, the length is read from the file."},"title":{"type":"string","maxLength":200},"source_language":{"enum":["auto","ar","bn","yue","zh","cs","da","nl","en","fi","fr","de","el","he","hi","hu","id","it","ja","ko","ms","no","fa","pl","pt","ro","ru","es","sw","sv","tl","ta","th","tr","uk","ur","vi",null],"description":"The language this item is sung in, over the request's `source_language`. An album's applies to every song on it."}}}]}},"translate_to":{"type":["string","null"],"enum":["ar","bn","yue","zh","zh-Hant","cs","da","nl","en","fi","fr","de","el","he","hi","hu","id","it","ja","ko","ms","no","fa","pl","pt","ro","ru","es","sw","sv","tl","ta","th","tr","uk","ur","vi",null],"default":null},"source_language":{"enum":["auto","ar","bn","yue","zh","cs","da","nl","en","fi","fr","de","el","he","hi","hu","id","it","ja","ko","ms","no","fa","pl","pt","ro","ru","es","sw","sv","tl","ta","th","tr","uk","ur","vi"],"default":"auto","description":"The language sung, or `auto` to detect it. For every item without its own `source_language`."},"chords":{"type":"boolean","default":false,"description":"The song's chords, detected from the recording and placed on the timed words. 1 credit more a song, given back when no chords can be made."},"published_lyrics":{"type":"boolean","default":false,"description":"Free: look each Spotify song up in published-lyrics databases (LRCLIB, then lyrics.ovh) instead of transcribing it. Found songs come back completed, with LRCLIB's line timings when it has them; songs not found, videos and uploads are skipped. 404 `no_published_lyrics` when none is found; 503 `lyrics_lookup_unavailable` when the databases didn't answer (try again); 400 `published_spotify_only` when no item is a Spotify link. Not with `chords` or `translate_to`."},"metadata":{"type":["object","null"],"description":"Any JSON object up to 1024 bytes, echoed back."}}},"CreateJobsResponse":{"type":"object","required":["data","skipped","message"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Job"}},"skipped":{"type":"integer","description":"Songs left out: over 30 minutes, an upload another job holds, or, with `published_lyrics`, no published lyrics found."},"message":{"type":["string","null"],"description":"Why songs were skipped, in words."}}},"LyricSheet":{"type":"object","required":["segments"],"properties":{"title":{"type":["string","null"]},"artist":{"type":["string","null"]},"provenance":{"type":"string","description":"How the text was made."},"segments":{"type":"array","items":{"$ref":"#/components/schemas/Line"}},"translated_segments":{"type":"array","items":{"$ref":"#/components/schemas/Line"},"description":"One for one with `segments`."},"language":{"type":"string"},"target_lang":{"type":"string"},"translation_skipped":{"enum":["same_language","failed"],"description":"On a job made with `translate_to` whose sheet has no translation: `same_language` when the song is already sung in that language, `failed` when the translation couldn't be made and the sheet came back untranslated. `translation_refunded` says whether the translation credit came back."},"translation_refunded":{"type":"boolean","description":"Set with `translation_skipped`: true when the translation credit was given back. False on the free song, which wasn't charged for it."},"translation_coverage":{"type":"number","minimum":0,"maximum":1,"description":"Share of the sung lines that got a translation, set only when some didn't; those lines' `translated_segments` entries have empty text."},"timed":{"type":"boolean","description":"The lines have `start` and `end`: every transcribed sheet, and published lyrics with line timings."},"word_timing":{"type":"boolean","description":"The lines carry `words`."},"instrumental":{"type":"boolean"},"chords":{"type":"array","items":{"$ref":"#/components/schemas/Chord"},"description":"On a job made with `chords`: the song's chords by time, never tied to a line. Place them on the words by their times."},"key":{"type":"object","required":["tonic","mode"],"properties":{"tonic":{"type":"string","examples":["D#"]},"mode":{"enum":["major","minor"]}},"description":"The key the chords were estimated in."},"beats":{"type":"array","items":{"type":"number"},"description":"Beat times in seconds."},"downbeats":{"type":"array","items":{"type":"number"},"description":"Downbeat times in seconds."},"chords_status":{"enum":["made","failed"],"description":"On a job made with `chords`: `failed` when none could be made. `chords_refunded` says whether the chord credit came back."},"chords_refunded":{"type":"boolean","description":"Set with `chords_status: failed`: true when the chord credit was given back. False on the free song, which wasn't charged for it, and when giving it back failed (`chords_refund_owed`)."},"chords_refund_owed":{"type":"boolean","description":"True when the chord credit couldn't be given back automatically. Email support@lyricbook.ai with the job id and it will be."}}},"Chord":{"type":"object","required":["start","end","label"],"properties":{"start":{"type":"number","description":"Seconds from the start of the track."},"end":{"type":"number"},"label":{"type":"string","description":"Harte syntax: `C`, `A:min7`, `F:maj/3` (F major over A), `N` for no chord.","examples":["A:min7"]},"conf":{"type":"number","description":"Share of the recognisers that agree with the chord's major or minor family, 0 to 1. Under 0.6 it is right less than half the time."},"alt":{"type":"array","items":{"type":"string"},"description":"Up to two other chords the recognisers heard there."}}},"Line":{"type":"object","required":["text"],"properties":{"text":{"type":"string"},"start":{"type":"number","description":"Seconds from the start of the track."},"end":{"type":"number"},"break":{"type":"boolean","description":"A stanza break comes before this line."},"words":{"type":"array","description":"On a word-timed sheet: each word's times. Joined, the texts are exactly `text` (a space belongs to the word before it); Japanese and Chinese are timed per character. Never on translated lines.","items":{"type":"object","required":["text","start","end"],"properties":{"text":{"type":"string"},"start":{"type":"number"},"end":{"type":"number"}}}}}},"Quote":{"type":"object","required":["source","kind","title","url","translate_to","chords","track_count","duration_ms","credits","message","tracks"],"properties":{"source":{"enum":["spotify","youtube"]},"kind":{"enum":["track","album","video"]},"title":{"type":"string"},"subtitle":{"type":"string"},"artwork_url":{"type":["string","null"]},"url":{"type":"string"},"translate_to":{"type":["string","null"],"description":"The `translate_to` priced, or null."},"chords":{"type":"boolean","description":"Priced with chords."},"track_count":{"type":"integer"},"duration_ms":{"type":"integer"},"credits":{"type":"number","description":"What the jobs cost: every song transcribed and timed, at 1 credit a minute, 1 more each when translating and 1 more each with chords."},"message":{"type":["string","null"],"description":"On a Spotify quote: that its songs' published lyrics, where they exist, are free with `published_lyrics`."},"tracks":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"artist":{"type":["string","null"]},"url":{"type":"string"},"duration_ms":{"type":"integer"},"credits":{"type":"number","description":"Its minutes, 1 more when translating and 1 more for chords; 0 when too long."},"too_long":{"type":"boolean","description":"Over 30 minutes: skipped when sent."}}}}}},"Account":{"type":"object","required":["object","credits","free_song","limits"],"properties":{"object":{"const":"account"},"credits":{"type":"number"},"free_song":{"type":"object","properties":{"available":{"type":"boolean"},"max_minutes":{"type":"integer"}}},"limits":{"type":"object","properties":{"songs_in_progress":{"type":"integer"},"songs_running":{"type":"integer"},"songs_per_day":{"type":"integer"},"songs_per_request":{"type":"integer"},"max_song_minutes":{"type":"integer"},"unsent_uploads":{"type":"integer"},"unsent_upload_bytes":{"type":"integer"},"upload_max_bytes":{"type":"integer"}}}}},"CreateUploadRequest":{"type":"object","required":["filename","size_bytes"],"properties":{"filename":{"type":"string","description":"With its extension: mp3, m4a, aac, wav, flac, ogg, opus, aiff, aif, wma."},"size_bytes":{"type":"integer","minimum":1,"maximum":52428800}}},"Upload":{"type":"object","required":["object","upload_id","filename","size_bytes","expires_at","upload"],"properties":{"object":{"const":"upload"},"upload_id":{"type":"string"},"filename":{"type":"string"},"size_bytes":{"type":"integer"},"expires_at":{"type":"string","format":"date-time"},"upload":{"type":"object","required":["method","url","headers"],"properties":{"method":{"const":"PUT"},"url":{"type":"string","format":"uri"},"headers":{"type":"object","additionalProperties":{"type":"string"}}}}}},"JobEvent":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as the webhook-id header."},"type":{"enum":["job.completed","job.failed","job.refunded"]},"timestamp":{"type":"string","format":"date-time"},"data":{"$ref":"#/components/schemas/Job"}}},"TestEvent":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string"},"type":{"const":"webhook.test"},"timestamp":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}