{"openapi":"3.1.0","info":{"title":"Kinetune API","version":"1","description":"Lyric videos and Spotify Canvas loops from your songs. The same operations power the app, the MCP server, the CLI and the n8n node."},"servers":[{"url":"https://kinetune.com"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"An organization API key (kt_live_…) or an OAuth access token"},"oauth2":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://kinetune.com/api/auth/oauth2/authorize","tokenUrl":"https://kinetune.com/api/auth/oauth2/token","scopes":{"videos:read":"See videos, quotes and your credit balance","videos:write":"Quote, create, cancel, retry and delete videos (spends credits)","music:read":"See artists, their photos and songs","music:write":"Add, rename and archive artists and songs, upload songs and artist photos","library:read":"Browse Looks","library:write":"Rename, delete and publish your Looks","organizations:read":"See the workspaces you belong to","organizations:write":"Create workspaces you own, and rename or switch the type of one you own or run"}}}}},"schemas":{"Video":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["lyric-video","canvas"]},"variation":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"variation_count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"quote_id":{"type":["string","null"]},"status":{"type":"string","enum":["queued","processing","completed","failed","cancelled"]},"stage":{"type":"string","description":"The step it is at while it is made"},"progress":{"type":"number","description":"0–100"},"queue":{"anyOf":[{"type":"object","properties":{"reason":{"type":"string","enum":["plan_limit","render_capacity"],"description":"plan_limit: the organization already makes as many videos at once as its plan allows, so this one starts when one of them finishes. render_capacity: every render machine is busy, so parts of this video wait their turn (higher plans get a larger share of the machines)"},"position":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"plan_limit: its place among the organization's waiting videos (1 starts next); null otherwise"},"estimated_wait_seconds":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}],"description":"render_capacity: about how long until all of it is rendering, in seconds; null otherwise"}},"required":["reason","position","estimated_wait_seconds"],"additionalProperties":false},{"type":"null"}],"description":"Why the video is waiting, while it waits (its plan's limit, or every render machine busy); null otherwise"},"outputs":{"type":"array","items":{"type":"object","properties":{"aspect_ratio":{"type":"string","enum":["9:16","16:9","1:1"],"description":"The format of this file"},"url":{"description":"The full-quality file","type":"string"},"download_url":{"description":"The full-quality file, saved under a readable name","type":"string"},"web_url":{"description":"A 720p copy, for playback","type":"string"},"poster_url":{"description":"A still of the video: for a lyric video one whole lyric line on screen (the hook when it can be), for a Canvas its first frame","type":"string"},"poster_seconds":{"description":"Where poster_url was cut, in seconds from the start of this file (a trimmed clip counts from its own start): the cover frame offset for a post that takes one instead of an image (TikTok). Null for videos made before it was kept","type":["number","null"]},"url_expires_in_seconds":{"description":"How long the links stay valid","type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"duration_seconds":{"type":["number","null"]},"size_bytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"bitrate_kbps":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]},"web_size_bytes":{"anyOf":[{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},{"type":"null"}]}},"required":["aspect_ratio","poster_seconds"],"additionalProperties":{}},"description":"One file per format, once delivered"},"song":{"type":"object","properties":{"id":{"type":["string","null"]},"title":{"type":["string","null"]},"artist_name":{"type":["string","null"]}},"required":["id","title","artist_name"],"additionalProperties":false},"request":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"What the video was made from, with your metadata"},"look_id":{"type":["string","null"]},"look":{"anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"canvas":{"description":"A Canvas: its design and, for stock, the credit to show","anyOf":[{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},{"type":"null"}]},"quoted_credits":{"type":["number","null"]},"charged_credits":{"type":["number","null"]},"error":{"type":["string","null"]},"error_code":{"type":["string","null"]},"retry_of_job_id":{"type":["string","null"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","type","variation","variation_count","quote_id","status","stage","progress","queue","outputs","song","request","look_id","look","quoted_credits","charged_credits","error","error_code","retry_of_job_id","created_at","updated_at"],"additionalProperties":{}}}},"paths":{"/api/v1/account":{"get":{"operationId":"account.get","summary":"Get the account","description":"Who you are signed in as, the organization (workspace) and its credit balance\n\nReturns the organization the credentials act for (the workspace, as the app calls it; type artist holds one artist, label a roster), how they authenticate and their scopes, the credit balance (available, monthly, top-ups) and its plan, if any: active says whether it lets the workspace create (without an active plan, creating answers 402 plan_required: tell the person to choose a plan in the app), storage (used_bytes against limit_bytes, what the plan allows: an upload or new video that does not fit answers 402 storage_full, and deleting videos or archiving songs frees space at once), where it is billed, when the period ends, and a downgrade or interval switch waiting for the renewal as scheduled_change. Monthly credits reset every month; top-ups never expire. Check it before creating anything.","tags":["account"],"parameters":[],"security":[{"bearer":[]},{"oauth2":["videos:read","music:read","library:read"]}],"x-operations":[{"id":"account.get","mcpTool":"get_account","cli":"kinetune account"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/options":{"get":{"operationId":"options.get","summary":"List the options","description":"Video types, Look categories, background sources, formats and the current credit prices\n\nEverything a request can choose from, with the credit table, and the plans on sale (plans: each plan's monthly and yearly price in cents, monthly credits and limits). Use it to pick a category or source and to explain prices.","tags":["account"],"parameters":[],"security":[{"bearer":[]},{"oauth2":["videos:read","music:read","library:read"]}],"x-operations":[{"id":"options.get","mcpTool":"get_options","cli":"kinetune options"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/organizations":{"get":{"operationId":"organizations.list","summary":"List your organizations","description":"The organizations you belong to, your role in each and the one these credentials act for\n\nEvery organization (workspace, in the app) the signed-in person is a member of; with an API key, the member who created it (the key needs organizations:read). type is artist (one artist and its songs) or label (a roster of artists). current marks the organization these credentials act for. Each organization has its own plan, music, videos, Looks and credits: to work in another one, sign in again and pick it on the consent screen, or use an API key created in it.","tags":["account"],"parameters":[],"security":[{"bearer":[]},{"oauth2":["organizations:read"]}],"x-operations":[{"id":"organizations.list","mcpTool":"list_organizations","cli":"kinetune organizations list"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"post":{"operationId":"organizations.create","summary":"Create an organization","description":"A new organization owned by you, with its own music, videos, Looks and credits\n\nCreates an empty organization (a workspace, in the app) with the signed-in person as its owner; with an API key, the member who created the key (the key needs organizations:write). type artist is for one artist (add that artist next with create_artist; its songs then need no artist_id), label for a roster. It starts with no plan and no credits: the owner chooses a plan in the app before anything can be created in it. These credentials keep acting for their current organization: to work in the new one, sign in again and pick it, or create an API key in it.","tags":["account"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Create an organization","properties":{"name":{"type":"string","minLength":2,"maxLength":80,"description":"The workspace name, as people see it in the app (an artist workspace usually carries the artist name)"},"type":{"type":"string","enum":["artist","label"],"description":"artist: one artist and its songs; label: a roster of artists"}},"required":["name","type"]}}}},"security":[{"bearer":[]},{"oauth2":["organizations:write"]}],"x-operations":[{"id":"organizations.create","mcpTool":"create_organization","cli":"kinetune organizations create"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/organization":{"patch":{"operationId":"organizations.update","summary":"Update the organization","description":"Rename the organization (workspace) these credentials act for, or switch it between artist and label\n\nOwners and admins only. An artist workspace can become a label any time; a label can become an artist workspace only while it has one artist or none (409 otherwise).","tags":["account"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Update the organization","properties":{"name":{"description":"The new workspace name","type":"string","minLength":2,"maxLength":80},"type":{"description":"artist (one artist) or label (a roster)","type":"string","enum":["artist","label"]}},"required":[]}}}},"security":[{"bearer":[]},{"oauth2":["organizations:write"]}],"x-operations":[{"id":"organizations.update","mcpTool":"update_organization","cli":"kinetune organizations update"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/artists":{"get":{"operationId":"artists.list","summary":"List artists","description":"Artists by name, with their song and photo counts and a picture\n\nSongs belong to an artist; create the artist first. Sorted by name, 50 per page by default: pass q to search by name, and limit/offset to page.","tags":["artists"],"parameters":[{"name":"q","in":"query","required":false,"schema":{"description":"Part of the artist name","type":"string","maxLength":100},"description":"Part of the artist name"},{"name":"limit","in":"query","required":false,"schema":{"description":"Results per page, 1-100 (default 50)","type":"integer","minimum":1,"maximum":100},"description":"Results per page, 1-100 (default 50)"},{"name":"offset","in":"query","required":false,"schema":{"description":"How many results to skip","type":"integer","minimum":0,"maximum":9007199254740991},"description":"How many results to skip"}],"security":[{"bearer":[]},{"oauth2":["music:read","videos:read"]}],"x-operations":[{"id":"artists.list","mcpTool":"list_artists","cli":"kinetune artists list"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"post":{"operationId":"artists.create","summary":"Create an artist","description":"Add an artist by name\n\nNames are unique per organization (409 when taken). An artist workspace holds one artist: a second one is refused (409) until the workspace becomes a label (update_organization). Works without a plan, so onboarding can add the artist first.","tags":["artists"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Create an artist","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"The artist name"}},"required":["name"]}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"artists.create","mcpTool":"create_artist","cli":"kinetune artists create"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/artists/{artist_id}":{"get":{"operationId":"artists.get","summary":"Get an artist","description":"One artist","tags":["artists"],"parameters":[{"name":"artist_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The artist id"},"description":"The artist id"}],"security":[{"bearer":[]},{"oauth2":["music:read","videos:read"]}],"x-operations":[{"id":"artists.get","mcpTool":"get_artist","cli":"kinetune artists get"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"patch":{"operationId":"artists.update","summary":"Rename an artist","description":"Change an artist’s name","tags":["artists"],"parameters":[{"name":"artist_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The artist id"},"description":"The artist id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Rename an artist","properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"The new name"}},"required":["name"]}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"artists.update","mcpTool":"rename_artist","cli":"kinetune artists rename"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"delete":{"operationId":"artists.archive","summary":"Archive an artist","description":"Remove an artist that has no songs\n\nRefused (409) while the artist still has songs.","tags":["artists"],"parameters":[{"name":"artist_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The artist id"},"description":"The artist id"}],"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"artists.archive","mcpTool":"archive_artist","cli":"kinetune artists archive"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/artists/{artist_id}/picture":{"post":{"operationId":"artists.set_picture","summary":"Set the artist picture","description":"Choose which photo is the artist’s picture, and how it is cropped to a square\n\nThe picture (image_url on the artist, a 512 px square) is cut from one of the artist’s photos; the photo itself is unchanged. The first photo becomes the picture automatically, centered. crop is in fractions of the photo (its url): x/y the top-left corner, size the side relative to the photo’s short side; leave it out to center.","tags":["artists"],"parameters":[{"name":"artist_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The artist id"},"description":"The artist id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Set the artist picture","properties":{"photo_id":{"type":"string","minLength":1,"maxLength":120,"description":"One of the artist’s photos (list_artist_photos)"},"crop":{"description":"The square to keep, in fractions of the photo; centered when omitted","type":"object","properties":{"x":{"type":"number","minimum":0,"maximum":1},"y":{"type":"number","minimum":0,"maximum":1},"size":{"type":"number","minimum":0.1,"maximum":1}},"required":["x","y","size"]}},"required":["photo_id"]}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"artists.set_picture","mcpTool":"set_artist_picture","cli":"kinetune artists picture"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/artists/{artist_id}/photos":{"get":{"operationId":"artist_photos.list","summary":"List artist photos","description":"The artist’s photos (identity references, up to 6)\n\nPhotos keep the artist recognizable when a Look or Canvas shows them; the cover art stays the creative source. url is the photo upright at up to 1536 px (what the AI receives; width and height describe it), thumbnail_url a copy 320 px on its short side for grids.","tags":["artists"],"parameters":[{"name":"artist_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The artist id"},"description":"The artist id"}],"security":[{"bearer":[]},{"oauth2":["music:read","videos:read"]}],"x-operations":[{"id":"artist_photos.list","mcpTool":"list_artist_photos","cli":"kinetune artists photos list"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"post":{"operationId":"artist_photos.add","summary":"Add artist photos","description":"Upload one or more photos of the artist (JPEG, PNG or WebP)\n\nUp to 6 per artist, at least 512 px on the short side, up to 15 MB each. Only with the rights to use them (rights_confirmed). They are identity references only: never shown publicly or used as they are. Each is kept upright at up to 1536 px, with a small thumbnail; the uploaded file itself is not kept. Needs an active plan (402 plan_required without one; get_account: plan.active) and room in its storage (402 storage_full when it would not fit; get_account: storage).","tags":["artists"],"parameters":[{"name":"artist_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The artist id"},"description":"The artist id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Add artist photos","properties":{"photo_urls":{"description":"Public https URLs of the photos (or upload files with the CLI)","minItems":1,"maxItems":6,"type":"array","items":{"type":"string","maxLength":2000,"format":"uri","description":"A public https URL of a photo"}},"rights_confirmed":{"type":"boolean","const":true,"description":"You have the rights to use these photos of the artist"}},"required":["rights_confirmed"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"photos":{"type":"array","items":{"type":"string","format":"binary"}}}}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"artist_photos.add","mcpTool":"add_artist_photos","cli":"kinetune artists photos add"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/artists/{artist_id}/photos/{photo_id}":{"delete":{"operationId":"artist_photos.delete","summary":"Delete an artist photo","description":"Remove one photo","tags":["artists"],"parameters":[{"name":"artist_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The artist id"},"description":"The artist id"},{"name":"photo_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The photo id"},"description":"The photo id"}],"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"artist_photos.delete","mcpTool":"delete_artist_photo","cli":"kinetune artists photos delete"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/songs":{"get":{"operationId":"songs.list","summary":"List songs","description":"Songs with their cover, duration and analysis status\n\nA song must be analyzed (analysis.status \"ready\") before videos can be made. 50 per page by default: pass q to search, and limit/offset to page. cover_art.url is the cover at up to 1536 px (JPEG; width and height describe it), preview_url a 640 px and thumbnail_url a 160 px WebP. Image links are signed for 7 days and stay the same all day, so they can be cached.","tags":["songs"],"parameters":[{"name":"artist_id","in":"query","required":false,"schema":{"description":"Only this artist’s songs","type":"string","minLength":1,"maxLength":120},"description":"Only this artist’s songs"},{"name":"q","in":"query","required":false,"schema":{"description":"Part of the song title or artist name","type":"string","maxLength":100},"description":"Part of the song title or artist name"},{"name":"limit","in":"query","required":false,"schema":{"description":"Results per page, 1-100 (default 50)","type":"integer","minimum":1,"maximum":100},"description":"Results per page, 1-100 (default 50)"},{"name":"offset","in":"query","required":false,"schema":{"description":"How many results to skip","type":"integer","minimum":0,"maximum":9007199254740991},"description":"How many results to skip"},{"name":"status","in":"query","required":false,"schema":{"description":"Only songs whose analysis has this status (ready = usable for videos)","type":"string","enum":["pending","processing","ready","failed"]},"description":"Only songs whose analysis has this status (ready = usable for videos)"},{"name":"sort","in":"query","required":false,"schema":{"description":"title (default): by artist then title; newest: latest uploads first","type":"string","enum":["title","newest"]},"description":"title (default): by artist then title; newest: latest uploads first"}],"security":[{"bearer":[]},{"oauth2":["music:read","videos:read"]}],"x-operations":[{"id":"songs.list","mcpTool":"list_songs","cli":"kinetune songs list"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"post":{"operationId":"songs.create","summary":"Upload a song","description":"Add a song: master audio and square cover art\n\nAudio: MP3, WAV or M4A up to 250 MB. Cover: a square JPEG or PNG, 1000–6000 px (3000×3000 recommended), up to 20 MB; it is kept at 1536, 640 and 160 px, not as uploaded. The song is analyzed next (lyrics, beats, sections): poll get_song until analysis.status is \"ready\", usually about a minute. Pass lyrics (or set them later with set_song_lyrics) to have the videos spell every word right. Needs an active plan (402 plan_required without one; get_account: plan.active) and room in its storage (402 storage_full when it would not fit; get_account: storage).","tags":["songs"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Upload a song","properties":{"artist_id":{"description":"The artist id. An artist workspace may leave it out: its songs are its artist's","type":"string","minLength":1,"maxLength":120},"title":{"type":"string","minLength":1,"maxLength":300,"description":"The song title"},"language":{"description":"Lyrics language (ISO 639-1, e.g. \"en\"); detected when omitted","type":"string","pattern":"^[a-z]{2,3}$"},"audio_url":{"type":"string","maxLength":2000,"format":"uri","description":"A public https URL of the master audio"},"cover_art_url":{"type":"string","maxLength":2000,"format":"uri","description":"A public https URL of the square cover art"},"lyrics":{"description":"Optional. The song’s lyrics as text: plain (Suno-style [Verse]/[Chorus] tags and (x2) marks are fine), or the contents of an SRT, WebVTT or LRC file. Every word is still timed from the audio: your text fixes misheard words and sets where lines break in videos. A part sung again (a chorus) can be written once; lyrics that don’t match what’s sung, or cover only part of it, are refused once the song is analyzed (get_song: analysis.lyrics.status \"mismatch\")","type":"string","maxLength":100000}},"required":["title"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"audio":{"type":"string","format":"binary"},"cover_art":{"type":"string","format":"binary"}}}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"songs.create","mcpTool":"create_song","cli":"kinetune songs create"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/songs/{song_id}":{"get":{"operationId":"songs.get","summary":"Get a song","description":"One song and its analysis status\n\ncover_art.url is the cover at up to 1536 px (JPEG; width and height describe it), preview_url a 640 px and thumbnail_url a 160 px WebP. Image links are signed for 7 days and stay the same all day, so they can be cached. analysis.lyrics.status says whose words its videos show: \"transcribed\" (as heard), \"checked\" (your lyrics, timed from the audio; corrected, added and kept count what checking did), \"waiting\" (your lyrics, checked once the analysis finishes) or \"mismatch\" (your lyrics didn’t match what’s sung, so the transcription is used).","tags":["songs"],"parameters":[{"name":"song_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"description":"The song id"}],"security":[{"bearer":[]},{"oauth2":["music:read","videos:read"]}],"x-operations":[{"id":"songs.get","mcpTool":"get_song","cli":"kinetune songs get"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"patch":{"operationId":"songs.update","summary":"Rename a song","description":"Change a song’s title","tags":["songs"],"parameters":[{"name":"song_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"description":"The song id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Rename a song","properties":{"title":{"type":"string","minLength":1,"maxLength":300,"description":"The new title"}},"required":["title"]}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"songs.update","mcpTool":"rename_song","cli":"kinetune songs rename"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"delete":{"operationId":"songs.archive","summary":"Archive a song","description":"Remove a song (its videos stay)","tags":["songs"],"parameters":[{"name":"song_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"description":"The song id"}],"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"songs.archive","mcpTool":"archive_song","cli":"kinetune songs archive"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/songs/{song_id}/analysis":{"get":{"operationId":"songs.analysis","summary":"Get a song’s analysis","description":"Word-timed lyrics, tempo, beats, sections and hook\n\nUse the section times to choose a trim for a lyric video. lyrics.text is the song’s lyrics to edit: yours as you gave them, or the transcription a line per phrase (lyrics.yours says which).","tags":["songs"],"parameters":[{"name":"song_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"description":"The song id"}],"security":[{"bearer":[]},{"oauth2":["music:read","videos:read"]}],"x-operations":[{"id":"songs.analysis","mcpTool":"get_song_analysis","cli":"kinetune songs analysis"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"post":{"operationId":"songs.reanalyze","summary":"Analyze a song again","description":"Retry a failed analysis","tags":["songs"],"parameters":[{"name":"song_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"description":"The song id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Analyze a song again","properties":{},"required":[]}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"songs.reanalyze","mcpTool":"reanalyze_song","cli":"kinetune songs reanalyze"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/songs/{song_id}/lyrics":{"post":{"operationId":"songs.set_lyrics","summary":"Set a song’s lyrics","description":"Give a song its own lyrics, or replace them\n\nThe song’s lyrics as text: plain (Suno-style [Verse]/[Chorus] tags and (x2) marks are fine), or the contents of an SRT, WebVTT or LRC file. Every word is still timed from the audio: your text fixes misheard words and sets where lines break in videos. A part sung again (a chorus) can be written once; lyrics that don’t match what’s sung, or cover only part of it, are refused (409, the song unchanged). They are checked right away (analysis.lyrics in the answer says what changed), or once the analysis finishes if it hasn’t (202). Videos made from then on use them; videos already made stay as they are.","tags":["songs"],"parameters":[{"name":"song_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"description":"The song id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Set a song’s lyrics","properties":{"lyrics":{"type":"string","minLength":1,"maxLength":100000,"description":"The lyrics: text, or an SRT, WebVTT or LRC file’s contents"}},"required":["lyrics"]}}}},"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"songs.set_lyrics","mcpTool":"set_song_lyrics","cli":"kinetune songs set-lyrics"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"delete":{"operationId":"songs.clear_lyrics","summary":"Remove a song’s lyrics","description":"Go back to the transcribed words\n\nVideos made from then on show the words as transcribed.","tags":["songs"],"parameters":[{"name":"song_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"description":"The song id"}],"security":[{"bearer":[]},{"oauth2":["music:write","videos:write"]}],"x-operations":[{"id":"songs.clear_lyrics","mcpTool":"clear_song_lyrics","cli":"kinetune songs clear-lyrics"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/looks":{"get":{"operationId":"looks.list","summary":"List Looks","description":"Browse Official, Community and your own Looks\n\nA Look is a complete, reusable lyric-video design. Pass its id as {\"mode\":\"existing\",\"id\":…} to reuse it exactly. A Look that shows an artist (featured_artist) is private and only serves that artist's songs: choosing for a song, pass its artist_id to leave out Looks that show another artist.","tags":["looks"],"parameters":[{"name":"scope","in":"query","required":false,"schema":{"description":"Which library; default all","type":"string","enum":["all","official","community","mine"]},"description":"Which library; default all"},{"name":"category","in":"query","required":false,"schema":{"description":"A category id from get_options","type":"string","maxLength":40},"description":"A category id from get_options"},{"name":"lyric_style","in":"query","required":false,"schema":{"description":"A lyric style id from get_options (how the lyrics move)","type":"string","maxLength":40},"description":"A lyric style id from get_options (how the lyrics move)"},{"name":"artist_id","in":"query","required":false,"schema":{"description":"The artist of the song you are choosing for: Looks that show another artist are left out","type":"string","minLength":1,"maxLength":120},"description":"The artist of the song you are choosing for: Looks that show another artist are left out"},{"name":"q","in":"query","required":false,"schema":{"description":"Search words","type":"string","maxLength":100},"description":"Search words"},{"name":"sort","in":"query","required":false,"schema":{"type":"string","enum":["newest","popular"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":9007199254740991}}],"security":[{"bearer":[]},{"oauth2":["library:read","videos:read"]}],"x-operations":[{"id":"looks.list","mcpTool":"list_looks","cli":"kinetune looks list"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/looks/{look_id}":{"get":{"operationId":"looks.get","summary":"Get a Look","description":"One Look with its design and preview images\n\nbackgrounds.portrait and backgrounds.landscape are the background plates the video uses; backgrounds.previews has 480 px wide copies of them for thumbnails (null for a Look without a photo or video background).","tags":["looks"],"parameters":[{"name":"look_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The Look id"},"description":"The Look id"}],"security":[{"bearer":[]},{"oauth2":["library:read","videos:read"]}],"x-operations":[{"id":"looks.get","mcpTool":"get_look","cli":"kinetune looks get"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"patch":{"operationId":"looks.rename","summary":"Rename a Look","description":"Rename one of your Looks","tags":["looks"],"parameters":[{"name":"look_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The Look id"},"description":"The Look id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Rename a Look","properties":{"name":{"type":"string","minLength":2,"maxLength":60,"description":"The new name"}},"required":["name"]}}}},"security":[{"bearer":[]},{"oauth2":["library:write","videos:write"]}],"x-operations":[{"id":"looks.rename","mcpTool":"rename_look","cli":"kinetune looks rename"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"delete":{"operationId":"looks.delete","summary":"Delete a Look","description":"Remove one of your Looks (videos made with it stay)","tags":["looks"],"parameters":[{"name":"look_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The Look id"},"description":"The Look id"}],"security":[{"bearer":[]},{"oauth2":["library:write","videos:write"]}],"x-operations":[{"id":"looks.delete","mcpTool":"delete_look","cli":"kinetune looks delete"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/looks/{look_id}/visibility":{"post":{"operationId":"looks.visibility","summary":"Publish or unpublish a Look","description":"Make one of your Looks public (earns 10 credits) or private\n\nPublic Looks join the Community library under your @username. A Look that shows your artist stays private (409).","tags":["looks"],"parameters":[{"name":"look_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The Look id"},"description":"The Look id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Publish or unpublish a Look","properties":{"visibility":{"type":"string","enum":["public","private"]}},"required":["visibility"]}}}},"security":[{"bearer":[]},{"oauth2":["library:write","videos:write"]}],"x-operations":[{"id":"looks.visibility","mcpTool":"set_look_visibility","cli":"kinetune looks visibility"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/backgrounds":{"post":{"operationId":"backgrounds.upload","summary":"Upload a background","description":"Upload your own photo or video to design a New Look around\n\nPhoto: JPEG, PNG or WebP, at least 720 px on the short side, up to 25 MB. Video: MP4, MOV or WebM, 4–180 seconds, at least 720 px on the short side, up to 300 MB; it becomes a seamless loop of up to 20 s. Only with the rights to use it. Then quote a lyric video with look {\"mode\":\"new\",\"category\":\"…\",\"background\":{\"source\":\"upload-photo\" or \"upload-video\",\"upload_id\":\"…\"},\"visibility\":\"private\"}. Needs an active plan (402 plan_required without one; get_account: plan.active) and room in its storage (402 storage_full when it would not fit; get_account: storage).","tags":["looks"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Upload a background","properties":{"file_url":{"type":"string","maxLength":2000,"format":"uri","description":"A public https URL of the photo or video"},"rights_confirmed":{"type":"boolean","const":true,"description":"You have the rights to use this photo or video"}},"required":["rights_confirmed"]}},"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary"}}}}}},"security":[{"bearer":[]},{"oauth2":["library:write","videos:write"]}],"x-operations":[{"id":"backgrounds.upload","mcpTool":"upload_background","cli":"kinetune backgrounds upload"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/stock":{"get":{"operationId":"stock.search","summary":"Search stock media","description":"Find stock photos or clips to use as a background\n\n24 results a page. Pass an item's id as look.background.stock_id (source \"stock-photo\" or \"stock-video\") or as a Canvas's stock_id to use it instead of the director's pick, and credit the photographer (credit) wherever you show it. orientation: portrait for 9:16 and 1:1, landscape when 16:9 is among the formats (a Canvas is portrait). Clips too short for the loop are left out: pass seconds for a Canvas. thumbnail_url is a 480 px still, preview_url a 1280 px one (the photo, or the clip's poster), preview_video_url a small MP4 of a clip.","tags":["looks"],"parameters":[{"name":"kind","in":"query","required":true,"schema":{"type":"string","enum":["photo","video"],"description":"photo for stock-photo, video for stock-video"},"description":"photo for stock-photo, video for stock-video"},{"name":"q","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":100,"description":"Search words, e.g. \"foggy pine forest\""},"description":"Search words, e.g. \"foggy pine forest\""},{"name":"orientation","in":"query","required":false,"schema":{"description":"Default portrait","type":"string","enum":["portrait","landscape"]},"description":"Default portrait"},{"name":"page","in":"query","required":false,"schema":{"description":"Default 1; next_page says whether there are more","type":"integer","minimum":1,"maximum":50},"description":"Default 1; next_page says whether there are more"},{"name":"seconds","in":"query","required":false,"schema":{"description":"Clips for a Canvas of this length (5–8); omit for a Look's loop","type":"integer","minimum":5,"maximum":8},"description":"Clips for a Canvas of this length (5–8); omit for a Look's loop"}],"security":[{"bearer":[]},{"oauth2":["videos:read","videos:write","library:read"]}],"x-operations":[{"id":"stock.search","mcpTool":"search_stock","cli":"kinetune stock search"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/quotes":{"post":{"operationId":"quotes.create","summary":"Quote a lyric video or Quote a Canvas","description":"The exact credits for a lyric video, before anything is charged\n\nReturns quote_id, credits (total), credits_per_video and a breakdown. Always quote first and tell the user the credits before creating; credits are reserved at creation and charged only when the video is delivered. A quote is valid for 30 minutes.\n\nThe exact credits for a Spotify Canvas, before anything is charged\n\nReturns quote_id, credits and a breakdown. Always quote first and tell the user the credits before creating; credits are reserved at creation and charged only when the video is delivered.","tags":["videos"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","title":"Quote a lyric video","properties":{"type":{"const":"lyric-video"},"song_id":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"variations":{"default":1,"description":"1–4 different New Looks, one video each (an Existing Look renders one)","type":"integer","minimum":1,"maximum":4},"callback_url":{"description":"An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value","type":"string","maxLength":2000},"metadata":{"description":"Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"look":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"new"},"category":{"type":"string","enum":["release","fall","halloween","christmas","summer","valentines","mood","retro","synthwave","street","nature","luxury","abstract","minimal","neon","pop-art","lo-fi","grunge","cosmic","cyber","dreamy"]},"background":{"default":{"quality":"high"},"type":"object","properties":{"source":{"type":"string","enum":["ai-image","ai-video","stock-photo","stock-video","upload-photo","upload-video","designed"]},"quality":{"default":"high","type":"string","enum":["standard","high","ultra"]},"upload_id":{"type":"string","minLength":1,"maxLength":120},"scenes":{"type":"integer","minimum":1,"maximum":4},"stock_id":{"type":"string","pattern":"^\\d{1,20}$"},"references":{"type":"string","enum":["none","stock"]}},"additionalProperties":false},"visibility":{"default":"private","type":"string","enum":["private","public"]},"direction":{"type":"string","maxLength":2000},"feature_artist":{"default":"never","type":"string","enum":["never","always"]},"lyric_style":{"type":"string","enum":["showcase","block-stack","punch","depth-scatter","neon","terminal","cinematic","player","lo-fi","zine","glitch","pop-art","dreamy","chrome","visualizer","minimal","outline","messages","vinyl","album","tv","cube","cassette","phone","glass","embers","ink","smoke","stardust","drip","rain","screen","behind","big-type"]}},"required":["mode","category"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"existing"},"id":{"type":"string","minLength":1,"maxLength":120},"lyric_style":{"type":"string","enum":["showcase","block-stack","punch","depth-scatter","neon","terminal","cinematic","player","lo-fi","zine","glitch","pop-art","dreamy","chrome","visualizer","minimal","outline","messages","vinyl","album","tv","cube","cassette","phone","glass","embers","ink","smoke","stardust","drip","rain","screen","behind","big-type"]}},"required":["mode","id"],"additionalProperties":false}],"description":"{\"mode\":\"existing\",\"id\":\"look_…\"} to reuse a saved Look (add \"lyric_style\" to render it in another lyric style, at no extra cost), or {\"mode\":\"new\",\"category\":\"…\",\"lyric_style\":\"…\",\"background\":{\"source\":\"ai-image\",\"quality\":\"high\"},\"visibility\":\"private\",\"direction\":\"…\"} to have one designed (background.source \"upload-photo\"/\"upload-video\" with background.upload_id from upload_background designs it around your own media; such a Look stays private. \"stock-photo\"/\"stock-video\" with background.stock_id from search_stock uses that stock photo or clip instead of the director's pick). lyric_style (optional, from get_options) sets how the lyrics are presented and animated: block-stack, punch, player, neon, terminal, cinematic… Omit it and the director picks one. background.scenes (2–4, AI image only) makes that many shots of the same world that cut on the song's sections, each priced like the first. background.references \"stock\" (AI image or AI video, default \"none\") with feature_artist \"always\" makes the background one real stock photo of a place the director picks, with the artist put into it and restyled a little for the Look; no extra cost. The singer is left out unless asked: feature_artist \"always\" (default \"never\") makes them the subject of the background, recognizable from their artist photos (add_artist_photos); it needs an AI image or AI video background, a private Look and display.cover false (the cover would hide them), and that Look then only serves this artist's songs. A saved Look that shows an artist (featured_artist) only serves that artist's songs, also with display.cover false"},"aspect_ratios":{"default":["9:16"],"description":"Formats to render, each its own file: \"9:16\" (vertical), \"16:9\" (wide), \"1:1\" (square)","minItems":1,"maxItems":3,"type":"array","items":{"type":"string","enum":["9:16","16:9","1:1"]}},"display":{"default":{"title":true,"artist":true,"cover":true,"lyrics":true,"badges":true},"description":"Which elements show (title, artist, cover, lyrics, badges, headline) and their sizes. cover must be false to show the artist in the background","type":"object","properties":{"title":{"default":true,"type":"boolean"},"artist":{"default":true,"type":"boolean"},"cover":{"default":true,"type":"boolean"},"lyrics":{"default":true,"type":"boolean"},"badges":{"default":true,"type":"boolean"},"headline":{"type":"string","enum":["none","new-release","out-now","coming-soon","listen-now"]},"cover_scale":{"type":"number","minimum":0.75,"maximum":1.25},"text_scale":{"type":"number","minimum":0.85,"maximum":1.3},"artist_scale":{"type":"number","minimum":0.85,"maximum":1.5},"spacing_scale":{"type":"number","minimum":0.75,"maximum":1.5}},"additionalProperties":false},"trim":{"description":"Render only this section of the song (at least 8 seconds)","type":"object","properties":{"start_seconds":{"type":"number","minimum":0},"end_seconds":{"type":"number","exclusiveMinimum":0}},"required":["start_seconds","end_seconds"],"additionalProperties":false}},"required":["type","song_id","look"]},{"type":"object","title":"Quote a Canvas","properties":{"type":{"const":"canvas"},"song_id":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"variations":{"default":1,"description":"1–4 different Canvases","type":"integer","minimum":1,"maximum":4},"callback_url":{"description":"An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value","type":"string","maxLength":2000},"metadata":{"description":"Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"source":{"default":"ai-video","description":"ai-video (default), ai-image, stock-photo or stock-video","type":"string","enum":["ai-video","ai-image","stock-photo","stock-video"]},"quality":{"default":"standard","description":"AI video model tier: standard or high","type":"string","enum":["standard","high"]},"resolution":{"default":"1080p","description":"1080p (1080×1920) or 720p","type":"string","enum":["720p","1080p"]},"style":{"description":"Optional visual style","type":"string","enum":["cinematic","dreamy","abstract","surreal","retro","minimal","dark","vibrant","nature","urban"]},"direction":{"description":"Optional mood, motifs or references; the concept still comes from the cover","type":"string","maxLength":2000},"feature_artist":{"default":"auto","description":"Whether the Canvas shows the artist: auto (the director decides), always or never (AI sources; needs artist photos for \"always\")","type":"string","enum":["auto","always","never"]},"seconds":{"default":8,"description":"Canvas length in whole seconds, 5–8 (default 8). Spotify loops it, so no part of the song is chosen","type":"integer","minimum":5,"maximum":8},"stock_id":{"description":"With a stock source: the stock photo or video (search_stock with seconds) to use instead of the director's pick","type":"string","pattern":"^\\d{1,20}$"}},"required":["type","song_id"]}]}}}},"security":[{"bearer":[]},{"oauth2":["videos:write","videos:read"]}],"x-operations":[{"id":"quotes.lyric_video","mcpTool":"quote_lyric_video","cli":"kinetune quote lyric-video"},{"id":"quotes.canvas","mcpTool":"quote_canvas","cli":"kinetune quote canvas"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/videos":{"post":{"operationId":"videos.create","summary":"Create a lyric video or Create a Canvas","description":"Make the lyric video a quote priced (spends credits)\n\nSend the same request as the quote plus its quote_id. Returns the video ids at once; poll get_video until status is completed (or failed). Each video has one file per format. Needs an active plan (402 plan_required without one; get_account: plan.active) and room in its storage (402 storage_full when it would not fit; get_account: storage).\n\nMake the Canvas a quote priced (spends credits)\n\nSend the same request as the quote plus its quote_id. Returns the video ids at once; poll get_video until status is completed. Upload the file in Spotify for Artists. Needs an active plan (402 plan_required without one; get_account: plan.active) and room in its storage (402 storage_full when it would not fit; get_account: storage).","tags":["videos"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","title":"Create a lyric video","properties":{"type":{"const":"lyric-video"},"song_id":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"variations":{"default":1,"description":"1–4 different New Looks, one video each (an Existing Look renders one)","type":"integer","minimum":1,"maximum":4},"callback_url":{"description":"An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value","type":"string","maxLength":2000},"metadata":{"description":"Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"look":{"oneOf":[{"type":"object","properties":{"mode":{"type":"string","const":"new"},"category":{"type":"string","enum":["release","fall","halloween","christmas","summer","valentines","mood","retro","synthwave","street","nature","luxury","abstract","minimal","neon","pop-art","lo-fi","grunge","cosmic","cyber","dreamy"]},"background":{"default":{"quality":"high"},"type":"object","properties":{"source":{"type":"string","enum":["ai-image","ai-video","stock-photo","stock-video","upload-photo","upload-video","designed"]},"quality":{"default":"high","type":"string","enum":["standard","high","ultra"]},"upload_id":{"type":"string","minLength":1,"maxLength":120},"scenes":{"type":"integer","minimum":1,"maximum":4},"stock_id":{"type":"string","pattern":"^\\d{1,20}$"},"references":{"type":"string","enum":["none","stock"]}},"additionalProperties":false},"visibility":{"default":"private","type":"string","enum":["private","public"]},"direction":{"type":"string","maxLength":2000},"feature_artist":{"default":"never","type":"string","enum":["never","always"]},"lyric_style":{"type":"string","enum":["showcase","block-stack","punch","depth-scatter","neon","terminal","cinematic","player","lo-fi","zine","glitch","pop-art","dreamy","chrome","visualizer","minimal","outline","messages","vinyl","album","tv","cube","cassette","phone","glass","embers","ink","smoke","stardust","drip","rain","screen","behind","big-type"]}},"required":["mode","category"],"additionalProperties":false},{"type":"object","properties":{"mode":{"type":"string","const":"existing"},"id":{"type":"string","minLength":1,"maxLength":120},"lyric_style":{"type":"string","enum":["showcase","block-stack","punch","depth-scatter","neon","terminal","cinematic","player","lo-fi","zine","glitch","pop-art","dreamy","chrome","visualizer","minimal","outline","messages","vinyl","album","tv","cube","cassette","phone","glass","embers","ink","smoke","stardust","drip","rain","screen","behind","big-type"]}},"required":["mode","id"],"additionalProperties":false}],"description":"{\"mode\":\"existing\",\"id\":\"look_…\"} to reuse a saved Look (add \"lyric_style\" to render it in another lyric style, at no extra cost), or {\"mode\":\"new\",\"category\":\"…\",\"lyric_style\":\"…\",\"background\":{\"source\":\"ai-image\",\"quality\":\"high\"},\"visibility\":\"private\",\"direction\":\"…\"} to have one designed (background.source \"upload-photo\"/\"upload-video\" with background.upload_id from upload_background designs it around your own media; such a Look stays private. \"stock-photo\"/\"stock-video\" with background.stock_id from search_stock uses that stock photo or clip instead of the director's pick). lyric_style (optional, from get_options) sets how the lyrics are presented and animated: block-stack, punch, player, neon, terminal, cinematic… Omit it and the director picks one. background.scenes (2–4, AI image only) makes that many shots of the same world that cut on the song's sections, each priced like the first. background.references \"stock\" (AI image or AI video, default \"none\") with feature_artist \"always\" makes the background one real stock photo of a place the director picks, with the artist put into it and restyled a little for the Look; no extra cost. The singer is left out unless asked: feature_artist \"always\" (default \"never\") makes them the subject of the background, recognizable from their artist photos (add_artist_photos); it needs an AI image or AI video background, a private Look and display.cover false (the cover would hide them), and that Look then only serves this artist's songs. A saved Look that shows an artist (featured_artist) only serves that artist's songs, also with display.cover false"},"aspect_ratios":{"default":["9:16"],"description":"Formats to render, each its own file: \"9:16\" (vertical), \"16:9\" (wide), \"1:1\" (square)","minItems":1,"maxItems":3,"type":"array","items":{"type":"string","enum":["9:16","16:9","1:1"]}},"display":{"default":{"title":true,"artist":true,"cover":true,"lyrics":true,"badges":true},"description":"Which elements show (title, artist, cover, lyrics, badges, headline) and their sizes. cover must be false to show the artist in the background","type":"object","properties":{"title":{"default":true,"type":"boolean"},"artist":{"default":true,"type":"boolean"},"cover":{"default":true,"type":"boolean"},"lyrics":{"default":true,"type":"boolean"},"badges":{"default":true,"type":"boolean"},"headline":{"type":"string","enum":["none","new-release","out-now","coming-soon","listen-now"]},"cover_scale":{"type":"number","minimum":0.75,"maximum":1.25},"text_scale":{"type":"number","minimum":0.85,"maximum":1.3},"artist_scale":{"type":"number","minimum":0.85,"maximum":1.5},"spacing_scale":{"type":"number","minimum":0.75,"maximum":1.5}},"additionalProperties":false},"trim":{"description":"Render only this section of the song (at least 8 seconds)","type":"object","properties":{"start_seconds":{"type":"number","minimum":0},"end_seconds":{"type":"number","exclusiveMinimum":0}},"required":["start_seconds","end_seconds"],"additionalProperties":false},"quote_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The quote_id from the matching quote: the request must be identical"}},"required":["type","song_id","look","quote_id"]},{"type":"object","title":"Create a Canvas","properties":{"type":{"const":"canvas"},"song_id":{"type":"string","minLength":1,"maxLength":120,"description":"The song id"},"variations":{"default":1,"description":"1–4 different Canvases","type":"integer","minimum":1,"maximum":4},"callback_url":{"description":"An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value","type":"string","maxLength":2000},"metadata":{"description":"Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value","type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"source":{"default":"ai-video","description":"ai-video (default), ai-image, stock-photo or stock-video","type":"string","enum":["ai-video","ai-image","stock-photo","stock-video"]},"quality":{"default":"standard","description":"AI video model tier: standard or high","type":"string","enum":["standard","high"]},"resolution":{"default":"1080p","description":"1080p (1080×1920) or 720p","type":"string","enum":["720p","1080p"]},"style":{"description":"Optional visual style","type":"string","enum":["cinematic","dreamy","abstract","surreal","retro","minimal","dark","vibrant","nature","urban"]},"direction":{"description":"Optional mood, motifs or references; the concept still comes from the cover","type":"string","maxLength":2000},"feature_artist":{"default":"auto","description":"Whether the Canvas shows the artist: auto (the director decides), always or never (AI sources; needs artist photos for \"always\")","type":"string","enum":["auto","always","never"]},"seconds":{"default":8,"description":"Canvas length in whole seconds, 5–8 (default 8). Spotify loops it, so no part of the song is chosen","type":"integer","minimum":5,"maximum":8},"stock_id":{"description":"With a stock source: the stock photo or video (search_stock with seconds) to use instead of the director's pick","type":"string","pattern":"^\\d{1,20}$"},"quote_id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$","description":"The quote_id from the matching quote: the request must be identical"}},"required":["type","song_id","quote_id"]}]}}}},"security":[{"bearer":[]},{"oauth2":["videos:write"]}],"x-operations":[{"id":"videos.create_lyric_video","mcpTool":"create_lyric_video","cli":"kinetune create lyric-video"},{"id":"videos.create_canvas","mcpTool":"create_canvas","cli":"kinetune create canvas"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"get":{"operationId":"videos.list","summary":"List videos","description":"Videos, newest first, with status and thumbnails\n\nEach video's outputs carry aspect_ratio, poster_url, poster_seconds and web_url (for thumbnails and previews); get_video has the download links. A video that is waiting has queue: why (plan_limit or render_capacity), its place in line or about how long.","tags":["videos"],"parameters":[{"name":"song_id","in":"query","required":false,"schema":{"description":"Only this song’s videos","type":"string","minLength":1,"maxLength":120},"description":"Only this song’s videos"},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["lyric-video","canvas"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"security":[{"bearer":[]},{"oauth2":["videos:read"]}],"x-operations":[{"id":"videos.list","mcpTool":"list_videos","cli":"kinetune videos list"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/videos/{video_id}":{"get":{"operationId":"videos.get","summary":"Get a video","description":"Status, progress, credits and, when completed, the download links\n\nstatus is queued, processing, completed, failed or cancelled. While it waits, queue says why: plan_limit (the organization already makes as many videos at once as its plan allows; position is its place in line) or render_capacity (every render machine is busy; estimated_wait_seconds is about how long). Completed videos have outputs with download_url (full quality), web_url (720p) and poster_url, signed for 7 days. A lyric video's poster is a frame with one whole lyric line on screen (the hook when it can be), ready to set as the thumbnail where you post it; a Canvas's is its first frame. poster_seconds says where in that file the poster was cut, for posts that take a cover frame offset instead of an image (TikTok); null on videos made before it was kept. Failed videos have error and error_code; AI_VIDEO_UNAVAILABLE means the AI video couldn’t be made for a reason on our side, so make it again later.","tags":["videos"],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The video id"},"description":"The video id"}],"security":[{"bearer":[]},{"oauth2":["videos:read"]}],"x-operations":[{"id":"videos.get","mcpTool":"get_video","cli":"kinetune videos get"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}},"delete":{"operationId":"videos.delete","summary":"Delete a video","description":"Delete a finished video and its files","tags":["videos"],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The video id"},"description":"The video id"}],"security":[{"bearer":[]},{"oauth2":["videos:write"]}],"x-operations":[{"id":"videos.delete","mcpTool":"delete_video","cli":"kinetune videos delete"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/videos/{video_id}/cancel":{"post":{"operationId":"videos.cancel","summary":"Cancel a video","description":"Stop a queued or processing video (credits released)","tags":["videos"],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The video id"},"description":"The video id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Cancel a video","properties":{},"required":[]}}}},"security":[{"bearer":[]},{"oauth2":["videos:write"]}],"x-operations":[{"id":"videos.cancel","mcpTool":"cancel_video","cli":"kinetune videos cancel"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}},"/api/v1/videos/{video_id}/retry":{"post":{"operationId":"videos.retry","summary":"Make a video again","description":"Run a finished, failed or cancelled video again (new charge)\n\nReuses the Look it made, with its background media and loops, so nothing already made is paid for again. A video that failed before its Look was saved is designed afresh.","tags":["videos"],"parameters":[{"name":"video_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120,"description":"The video id"},"description":"The video id"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","title":"Make a video again","properties":{},"required":[]}}}},"security":[{"bearer":[]},{"oauth2":["videos:write"]}],"x-operations":[{"id":"videos.retry","mcpTool":"retry_video","cli":"kinetune videos retry"}],"responses":{"200":{"description":"OK"},"201":{"description":"Created"},"400":{"description":"Invalid request"},"401":{"description":"Missing or invalid credentials"},"402":{"description":"Not enough credits, no active plan (code plan_required), or storage full (code storage_full)"},"403":{"description":"Missing scope"},"404":{"description":"Not found"},"409":{"description":"Conflict"},"422":{"description":"Unprocessable"},"503":{"description":"Temporarily unavailable (AI video): nothing was held; try again after Retry-After seconds"}}}}},"webhooks":{"video":{"post":{"operationId":"videos.callback","summary":"A video is finished","tags":["videos"],"description":"POSTed to the request's callback_url once the video is completed, failed or cancelled: the video as get_video returns it. Kinetune-Signature is t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<body>\"> with your callback secret. Answer with any 2xx within 10 seconds; anything else is retried after 30 s, 2 min, 10 min, 30 min and 2 h.","parameters":[{"name":"Kinetune-Event","in":"header","required":true,"schema":{"type":"string","enum":["video.completed","video.failed","video.cancelled"]}},{"name":"Kinetune-Delivery","in":"header","required":true,"description":"A new id for every attempt","schema":{"type":"string","format":"uuid"}},{"name":"Kinetune-Signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Video"}}}},"responses":{"2XX":{"description":"Received"}}}}}}