Kinetune
Turn songs into word-synced lyric videos (9:16, 16:9, 1:1) and Spotify Canvas loops. Upload a track, browse Looks, get an exact credit quote, then render and download.
Hosted MCP Server
npx add-mcp 'https://kinetune.com/mcp'Installs into Claude Code, Codex, Cursor and more
Documentation
Overview
One host serves everything, and every surface runs the same operations with the same validation and the same exact prices as the app.
Endpoints
REST API
https://kinetune.com/api/v1
MCP server
https://kinetune.com/mcp · Streamable HTTP
OpenAPI 3.1
https://kinetune.com/api/v1/openapi.json
OAuth discovery
https://kinetune.com/.well-known/oauth-authorization-server
How a video is made
- Add a song: the master audio and its square cover art. It is analyzed (lyrics, beats, sections) in about a minute.
- Quote the video you want. The quote is the exact number of credits; nothing is charged.
- Create it with the same request plus the
quote_id. Credits are held, and charged only when the video is delivered. - Wait for
status: "completed": poll the video or receive a signed callback. - Download the files: one MP4 per format, links valid for 7 days (ask again for fresh ones).
Quickstart
The same request three ways. Pick the one that matches where your code or agent runs.
Terminal
npm install -g @kinetune/cli
kinetune auth login # opens the browser to sign in
kinetune artists create --name "Nova Lane"
kinetune songs create --artist-id ARTIST_ID --title "Midnight Drive" \
--audio ./midnight-drive.wav --cover-art ./cover.jpg
kinetune songs get SONG_ID # wait for analysis.status "ready"
kinetune create canvas --song-id SONG_ID # quotes, shows the credits, asks first
kinetune videos wait VIDEO_ID
kinetune videos download VIDEO_ID
Authentication
Two kinds of credentials, both sent as a Bearer token and both scoped to one organization.
API keys — servers, CI and n8n
Create one on the API page in the app (owners and admins). The secret is shown once; we store only an HMAC. Keys act for the organization and are limited by your plan.
Header
Authorization: Bearer kt_live_YOUR_KEY
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
OAuth endpoints
Authorization server
https://kinetune.com/.well-known/oauth-authorization-server
MCP resource
https://kinetune.com/mcp · metadata at /.well-known/oauth-protected-resource/mcp
REST resource
https://kinetune.com/api/v1 · metadata at /.well-known/oauth-protected-resource/api/v1
Authorize · token
/api/auth/oauth2/authorize · /api/auth/oauth2/token
Send resource (RFC 8707) with the MCP or REST URL so the token's audience matches; unauthenticated calls answer 401 with a WWW-Authenticate header that points to the resource metadata.
MCP server
Remote agents use Kinetune through the Model Context Protocol: one tool per API operation, Streamable HTTP, sign-in with your account.
Server URL
https://kinetune.com/mcp
Also listed in the official MCP Registry (com.kinetune/kinetune), on Smithery, Glama and Cursor Directory.
- In ChatGPT, open Settings → Apps & Connectors → Advanced and turn on Developer mode (it depends on your plan and workspace settings).
- Choose Create, name it Kinetune, paste the server URL and pick OAuth.
- Sign in, choose the organization and approve. Then enable it in a chat from the tools menu.
Tools
The server is stateless (JSON responses, protocol 2025-11-25). Tools that create videos spend credits, so agents are instructed to quote first and ask. wait_for_video waits up to 55 seconds per call.
| Tool | What it does |
|---|---|
| get_account | Who you are signed in as, the organization and its credit balance |
| get_options | Video types, Look categories, background sources, formats and the current credit prices |
| list_artists | Artists by name, with their song and photo counts and a picture |
| create_artist | Add an artist by name |
| get_artist | One artist |
| rename_artist | Change an artist’s name |
| archive_artist destructive | Remove an artist that has no songs |
| set_artist_picture | Choose which photo is the artist’s picture, and how it is cropped to a square |
| list_artist_photos | The artist’s photos (identity references, up to 6) |
| add_artist_photos | Upload one or more photos of the artist (JPEG, PNG or WebP) |
| delete_artist_photo destructive | Remove one photo |
| list_songs | Songs with their cover, duration and analysis status |
| create_song | Add a song: master audio and square cover art |
| get_song | One song and its analysis status |
| rename_song | Change a song’s title |
| archive_song destructive | Remove a song (its videos stay) |
| get_song_analysis | Word-timed lyrics, tempo, beats, sections and hook |
| reanalyze_song | Retry a failed analysis |
| list_looks | Browse Official, Community and your own Looks |
| get_look | One Look with its design and preview images |
| rename_look | Rename one of your Looks |
| delete_look destructive | Remove one of your Looks (videos made with it stay) |
| set_look_visibility | Make one of your Looks public (earns 10 credits) or private |
| upload_background | Upload your own photo or video to design a New Look around |
| search_stock | Find Pexels photos or clips to use as a stock background |
| quote_lyric_video | The exact credits for a lyric video, before anything is charged |
| quote_canvas | The exact credits for a Spotify Canvas, before anything is charged |
| create_lyric_video | Make the lyric video a quote priced (spends credits) |
| create_canvas | Make the Canvas a quote priced (spends credits) |
| list_videos | Videos, newest first, with status and thumbnails |
| get_video | Status, progress, credits and, when completed, the download links |
| cancel_video destructive | Stop a queued or processing video (credits released) |
| retry_video | Run a finished, failed or cancelled video again (new charge) |
| delete_video destructive | Delete a finished video and its files |
| wait_for_video | Waits for a video to finish (up to 55 s per call), then returns it like get_video |
Prompts and resources
Clients that show prompts as commands get three ready-made starts: make_lyric_video, make_canvas and browse_looks. Each one follows the quote-first workflow.
Read-only resources mirror the API reads: kinetune://account and kinetune://options, plus templates for kinetune://songs/{song_id}, …/analysis, kinetune://looks/{look_id}, kinetune://videos/{video_id} and kinetune://artists/{artist_id}, all returned as JSON.
CLI
kinetune runs every operation from the terminal. It prints JSON whenever its output is piped, so local agents and scripts read it directly.
Install (Node 20+)
npm install -g @kinetune/cli
# or without installing:
npx @kinetune/cli --help
Sign in
kinetune auth login # browser sign-in, picks the organization
kinetune auth login --api-key kt_live_YOUR_KEY # or store an API key
kinetune auth status
Working with it
Commands follow the API: kinetune songs list --q "tide" --limit 20, kinetune looks get LOOK_ID, kinetune quote lyric-video --song-id SONG_ID. Path ids are arguments, fields are flags, and --input file.json (or - for stdin) takes the whole request. Files go up by path or https URL: --audio ./song.wav.
kinetune create … always quotes first and asks before charging; pass --yes or a ceiling with --max-credits 120 in scripts. kinetune videos wait and kinetune videos download finish the job.
Give a local agent (Codex, Cursor, opencode, Claude Code…) the Kinetune skill so it knows the workflow: npx skills add kinetune/skills. It's open source at kinetune/skills.
For agents
kinetune schema create canvas # JSON Schema of a command's input
kinetune openapi # the whole API as OpenAPI 3.1
kinetune songs list --json # JSON even in a terminal
Environment and exit codes
KINETUNE_API_KEY
An organization API key; wins over the stored sign-in (CI, servers).
KINETUNE_URL
Another deployment of the app (defaults to this site).
KINETUNE_CONFIG_DIR
Where credentials live; default ~/.config/kinetune (mode 600).
Exit codes
0 done · 1 API or network error · 2 invalid usage or over --max-credits · 3 not signed in or not allowed
REST API
JSON over HTTPS. Every request carries a Bearer credential; ids are prefixed strings; times are ISO 8601.
Basics
Base URL
https://kinetune.com/api/v1
Auth
Authorization: Bearer … — an API key or an OAuth access token
Uploads
multipart/form-data files, or JSON with public https URLs (audio_url, cover_art_url, photo_urls, file_url)
Your own background
POST /backgrounds takes your photo or video; a New Look with background.source upload-photo or upload-video and its upload_id is designed around it, with no media cost. Such a Look stays private.
Stock you choose
GET /stock?kind=photo&q=…&orientation=portrait searches Pexels (24 a page; landscape when 16:9 is among the formats, seconds for a Canvas clip). A stock source with look.background.stock_id (or a Canvas’s stock_id) uses that item instead of the director’s pick, which drops the pick from the quote. Credit the photographer wherever you show an item.
Quotes
Valid for a limited time and once; create with the identical request plus quote_id. Re-sending the same quote returns the videos it already made.
Download links
Signed, valid 7 days; GET /videos/{id} returns fresh ones
Images
Kept at the sizes they're used at, not as uploaded: a song's cover_art.url (1536 px JPEG), preview_url (640 px) and thumbnail_url (160 px WebP); an artist photo's url (1536 px) and thumbnail_url; a Look's backgrounds.previews (480 px wide). Image links are signed for 7 days and stay the same all day, so they cache well.
Lyric styles
A New Look takes look.lyric_style: how the lyrics are presented and animated (block-stack, punch, player, neon, terminal …). GET /options lists them; leave it out and the director picks one. An Existing Look takes it too, to render the same design in another style at no extra cost. GET /looks?lyric_style= filters the Library.
Scenes
An AI image background can be 2–4 shots of the same world that cut on the song’s sections: look.background.scenes (1 by default). Each scene is priced like the first.
Quote a lyric video with a New Look in a lyric style
curl -s https://kinetune.com/api/v1/quotes -H "Authorization: Bearer $KINETUNE_API_KEY" \
-H "content-type: application/json" -d '{
"type": "lyric-video", "song_id": "SONG_ID", "aspect_ratios": ["9:16", "16:9"],
"look": { "mode": "new", "category": "street", "lyric_style": "punch" }
}'
Upload files (multipart)
curl -s https://kinetune.com/api/v1/songs -H "Authorization: Bearer $KINETUNE_API_KEY" \
-F artist_id=ARTIST_ID -F title="Midnight Drive" \
-F [email protected] -F [email protected]
Callbacks
Pass callback_url (https, public) with the quote and the create call, and the video is POSTed to you when it completes, fails or is cancelled.
Delivery
Body
The video, exactly as GET /videos/{id} returns it
Headers
Kinetune-Event (video.completed, video.failed, video.cancelled) · Kinetune-Delivery (unique id) · Kinetune-Signature
Retries
Any 2xx within 10 seconds counts. Otherwise it retries after 30 s, 2 min, 10 min, 30 min and 2 h.
Signing secret
On the API page in the app (whsec_…); rotate it there.
Verify Kinetune-Signature (Node)
import { createHmac, timingSafeEqual } from "node:crypto";
// header: "t=1760000000,v1=5f2c…" body: the raw request body
export function verified(header, body, secret) {
const { t, v1 } = Object.fromEntries(header.split(",").map(p => p.split("=")));
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // replay window
const expected = createHmac("sha256", secret).update(\`${t}.${body}\`).digest("hex");
return v1?.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}
Errors and limits
Errors are JSON: {"error": "…"} plus details where useful (field errors, required and available credits).
Status codes
400
Invalid request; details.fieldErrors names the fields.
401
Missing, invalid or expired credentials (OAuth clients refresh and retry).
402
Not enough credits: required and available tell you how many.
403
The credentials lack the scope, or the action is reserved to the app.
404
Not found in this organization.
409
A state conflict: the song is still being analyzed, or the quote expired, was used or no longer matches.
Concurrent renders are limited by your plan; extra videos wait in the queue.
n8n
The community node covers the same operations: songs, artists and photos, Looks, quotes, videos and downloads.
- In a self-hosted n8n, open Settings → Community nodes → Install and enter
@kinetune/n8n-nodes-kinetune. - Create a Kinetune API credential with an API key from the app; the base URL is
https://kinetune.com. - Pick artists and songs from a searchable list, or switch the field to By ID for an id or an expression. List Artists and List Songs search and page like the API.
- Quote, then create with the quote id. To continue when the video is ready, set its callback URL to an n8n Webhook node.
API reference
Every operation with its REST call, CLI command and MCP tool. Generated from the same definitions the API validates with.
Account
Get the account
GET /api/v1/account
Who you are signed in as, the organization and its credit balance. Returns the organization the credentials act for, how they authenticate and their scopes, and the credit balance (available, monthly, top-ups). Check it before creating videos.
CLI kinetune account MCP get_account Scopes videos:read or music:read or library:read
No parameters.
List the options
GET /api/v1/options
Video types, Look categories, background sources, formats and the current credit prices. Everything a request can choose from, with the credit table. Use it to pick a category or source and to explain prices.
CLI kinetune options MCP get_options Scopes videos:read or music:read or library:read
No parameters.
Artists and photos
List artists
GET /api/v1/artists
Artists by name, with their song and photo counts and a picture. Songs 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.
CLI kinetune artists list MCP list_artists Scopes music:read or videos:read
| Field | Type | Description |
|---|---|---|
q query | string | Part of the artist name |
limit query | integer 1–100 | Results per page, 1-100 (default 50) |
offset query | integer 0–9007199254740991 | How many results to skip |
Create an artist
POST /api/v1/artists
Add an artist by name. Names are unique per organization (409 when taken).
CLI kinetune artists create MCP create_artist Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
name body · required | string | The artist name |
Get an artist
GET /api/v1/artists/{artist_id}
One artist.
CLI kinetune artists get MCP get_artist Scopes music:read or videos:read
| Field | Type | Description |
|---|---|---|
artist_id path · required | string | The artist id |
Rename an artist
PATCH /api/v1/artists/{artist_id}
Change an artist’s name.
CLI kinetune artists rename MCP rename_artist Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
artist_id path · required | string | The artist id |
name body · required | string | The new name |
Archive an artist
DELETE /api/v1/artists/{artist_id}
Remove an artist that has no songs. Refused (409) while the artist still has songs.
CLI kinetune artists archive MCP archive_artist Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
artist_id path · required | string | The artist id |
Set the artist picture
POST /api/v1/artists/{artist_id}/picture
Choose which photo is the artist’s picture, and how it is cropped to a square. The 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.
CLI kinetune artists picture MCP set_artist_picture Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
artist_id path · required | string | The artist id |
photo_id body · required | string | One of the artist’s photos (list_artist_photos) |
crop body | object | The square to keep, in fractions of the photo; centered when omitted |
List artist photos
GET /api/v1/artists/{artist_id}/photos
The artist’s photos (identity references, up to 6). Photos 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.
CLI kinetune artists photos list MCP list_artist_photos Scopes music:read or videos:read
| Field | Type | Description |
|---|---|---|
artist_id path · required | string | The artist id |
Add artist photos
POST /api/v1/artists/{artist_id}/photos
Upload one or more photos of the artist (JPEG, PNG or WebP). Up 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.
CLI kinetune artists photos add MCP add_artist_photos Scopes music:write or videos:write
Files: photos (multipart) or photo_urls (JSON).
| Field | Type | Description |
|---|---|---|
artist_id path · required | string | The artist id |
photo_urls body | URL[] (1–6) | Public https URLs of the photos (or upload files with the CLI) |
rights_confirmed body · required | true | You have the rights to use these photos of the artist |
Delete an artist photo
DELETE /api/v1/artists/{artist_id}/photos/{photo_id}
Remove one photo.
CLI kinetune artists photos delete MCP delete_artist_photo Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
artist_id path · required | string | The artist id |
photo_id path · required | string | The photo id |
Songs
List songs
GET /api/v1/songs
Songs with their cover, duration and analysis status. A 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.
CLI kinetune songs list MCP list_songs Scopes music:read or videos:read
| Field | Type | Description |
|---|---|---|
artist_id query | string | Only this artist’s songs |
q query | string | Part of the song title or artist name |
limit query | integer 1–100 | Results per page, 1-100 (default 50) |
offset query | integer 0–9007199254740991 | How many results to skip |
status query | "pending" | "processing" | "ready" | "failed" | Only songs whose analysis has this status (ready = usable for videos) |
sort query | "title" | "newest" | title (default): by artist then title; newest: latest uploads first |
Upload a song
POST /api/v1/songs
Add a song: master audio and square cover art. Audio: 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.
CLI kinetune songs create MCP create_song Scopes music:write or videos:write
Files: audio (multipart) or audio_url (JSON), cover_art (multipart) or cover_art_url (JSON).
| Field | Type | Description |
|---|---|---|
artist_id body · required | string | The artist id |
title body · required | string | The song title |
language body | string | Lyrics language (ISO 639-1, e.g. "en"); detected when omitted |
audio_url body | URL | A public https URL of the master audio |
cover_art_url body | URL | A public https URL of the square cover art |
Get a song
GET /api/v1/songs/{song_id}
One song and its analysis status. 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.
CLI kinetune songs get MCP get_song Scopes music:read or videos:read
| Field | Type | Description |
|---|---|---|
song_id path · required | string | The song id |
Rename a song
PATCH /api/v1/songs/{song_id}
Change a song’s title.
CLI kinetune songs rename MCP rename_song Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
song_id path · required | string | The song id |
title body · required | string | The new title |
Archive a song
DELETE /api/v1/songs/{song_id}
Remove a song (its videos stay).
CLI kinetune songs archive MCP archive_song Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
song_id path · required | string | The song id |
Get a song’s analysis
GET /api/v1/songs/{song_id}/analysis
Word-timed lyrics, tempo, beats, sections and hook. Use the section times to choose a trim for a lyric video.
CLI kinetune songs analysis MCP get_song_analysis Scopes music:read or videos:read
| Field | Type | Description |
|---|---|---|
song_id path · required | string | The song id |
Analyze a song again
POST /api/v1/songs/{song_id}/analysis
Retry a failed analysis.
CLI kinetune songs reanalyze MCP reanalyze_song Scopes music:write or videos:write
| Field | Type | Description |
|---|---|---|
song_id path · required | string | The song id |
Looks
List Looks
GET /api/v1/looks
Browse Official, Community and your own Looks. A 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.
CLI kinetune looks list MCP list_looks Scopes library:read or videos:read
| Field | Type | Description |
|---|---|---|
scope query | "all" | "official" | "community" | "mine" | Which library; default all |
category query | string | A category id from get_options |
lyric_style query | string | A lyric style id from get_options (how the lyrics move) |
artist_id query | string | The artist of the song you are choosing for: Looks that show another artist are left out |
q query | string | Search words |
sort query | "newest" | "popular" | — |
limit query | integer 1–100 | — |
offset query | integer 0–9007199254740991 | — |
Get a Look
GET /api/v1/looks/{look_id}
One Look with its design and preview images. backgrounds.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).
CLI kinetune looks get MCP get_look Scopes library:read or videos:read
| Field | Type | Description |
|---|---|---|
look_id path · required | string | The Look id |
Rename a Look
PATCH /api/v1/looks/{look_id}
Rename one of your Looks.
CLI kinetune looks rename MCP rename_look Scopes library:write or videos:write
| Field | Type | Description |
|---|---|---|
look_id path · required | string | The Look id |
name body · required | string | The new name |
Delete a Look
DELETE /api/v1/looks/{look_id}
Remove one of your Looks (videos made with it stay).
CLI kinetune looks delete MCP delete_look Scopes library:write or videos:write
| Field | Type | Description |
|---|---|---|
look_id path · required | string | The Look id |
Publish or unpublish a Look
POST /api/v1/looks/{look_id}/visibility
Make one of your Looks public (earns 10 credits) or private. Public Looks join the Community library under your @username. A Look that shows your artist stays private (409).
CLI kinetune looks visibility MCP set_look_visibility Scopes library:write or videos:write
| Field | Type | Description |
|---|---|---|
look_id path · required | string | The Look id |
visibility body · required | "public" | "private" | — |
Upload a background
POST /api/v1/backgrounds
Upload your own photo or video to design a New Look around. Photo: 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"}.
CLI kinetune backgrounds upload MCP upload_background Scopes library:write or videos:write
Files: file (multipart) or file_url (JSON).
| Field | Type | Description |
|---|---|---|
file_url body | URL | A public https URL of the photo or video |
rights_confirmed body · required | true | You have the rights to use this photo or video |
Quotes and videos
Quote a lyric video
POST /api/v1/quotes body {"type":"lyric-video"}
The exact credits for a lyric video, before anything is charged. Returns 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.
CLI kinetune quote lyric-video MCP quote_lyric_video Scopes videos:write or videos:read
| Field | Type | Description |
|---|---|---|
song_id body · required | string | The song id |
variations body | integer 1–4 | 1–4 different New Looks, one video each (an Existing Look renders one) Default 1. |
callback_url body | string | An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value |
metadata body | object | Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value |
look body · required | object | {"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 Pexels item 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. 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 body | "9:16" | "16:9" | "1:1"[] (1–3) | Formats to render, each its own file: "9:16" (vertical), "16:9" (wide), "1:1" (square) Default ["9:16"]. |
display body | object | Which elements show (title, artist, cover, lyrics, badges, headline) and their sizes. cover must be false to show the artist in the background Default {"title":true,"artist":true,"cover":true,"lyrics":true,"badges":true}. |
trim body | object | Render only this section of the song (at least 8 seconds) |
Quote a Canvas
POST /api/v1/quotes body {"type":"canvas"}
The exact credits for a Spotify Canvas, before anything is charged. Returns 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.
CLI kinetune quote canvas MCP quote_canvas Scopes videos:write or videos:read
| Field | Type | Description |
|---|---|---|
song_id body · required | string | The song id |
variations body | integer 1–4 | 1–4 different Canvases Default 1. |
callback_url body | string | An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value |
metadata body | object | Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value |
source body | "ai-video" | "ai-image" | "stock-photo" | "stock-video" | ai-video (default), ai-image, stock-photo or stock-video Default "ai-video". |
quality body | "standard" | "high" | AI video model tier: standard or high Default "standard". |
resolution body | "720p" | "1080p" | 1080p (1080×1920) or 720p Default "1080p". |
style body | "cinematic" | "dreamy" | "abstract" | "surreal" | "retro" | "minimal" | "dark" | "vibrant" | "nature" | "urban" | Optional visual style |
direction body | string | Optional mood, motifs or references; the concept still comes from the cover |
feature_artist body | "auto" | "always" | "never" | Whether the Canvas shows the artist: auto (the director decides), always or never (AI sources; needs artist photos for "always") Default "auto". |
seconds body | integer 5–8 | Canvas length in whole seconds, 5–8 (default 8). Spotify loops it, so no part of the song is chosen Default 8. |
stock_id body | string | With a stock source: the Pexels photo or video (search_stock with seconds) to use instead of the director's pick |
Create a lyric video
POST /api/v1/videos body {"type":"lyric-video"}
Make the lyric video a quote priced (spends credits). Send 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.
CLI kinetune create lyric-video MCP create_lyric_video Scopes videos:write
| Field | Type | Description |
|---|---|---|
song_id body · required | string | The song id |
variations body | integer 1–4 | 1–4 different New Looks, one video each (an Existing Look renders one) Default 1. |
callback_url body | string | An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value |
metadata body | object | Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value |
look body · required | object | {"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 Pexels item 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. 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 body | "9:16" | "16:9" | "1:1"[] (1–3) | Formats to render, each its own file: "9:16" (vertical), "16:9" (wide), "1:1" (square) Default ["9:16"]. |
display body | object | Which elements show (title, artist, cover, lyrics, badges, headline) and their sizes. cover must be false to show the artist in the background Default {"title":true,"artist":true,"cover":true,"lyrics":true,"badges":true}. |
trim body | object | Render only this section of the song (at least 8 seconds) |
quote_id body · required | uuid | The quote_id from the matching quote: the request must be identical |
Create a Canvas
POST /api/v1/videos body {"type":"canvas"}
Make the Canvas a quote priced (spends credits). Send 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.
CLI kinetune create canvas MCP create_canvas Scopes videos:write
| Field | Type | Description |
|---|---|---|
song_id body · required | string | The song id |
variations body | integer 1–4 | 1–4 different Canvases Default 1. |
callback_url body | string | An https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value |
metadata body | object | Your own JSON (an order id, for example): kept with the video and returned in its request. Quote and create with the same value |
source body | "ai-video" | "ai-image" | "stock-photo" | "stock-video" | ai-video (default), ai-image, stock-photo or stock-video Default "ai-video". |
quality body | "standard" | "high" | AI video model tier: standard or high Default "standard". |
resolution body | "720p" | "1080p" | 1080p (1080×1920) or 720p Default "1080p". |
style body | "cinematic" | "dreamy" | "abstract" | "surreal" | "retro" | "minimal" | "dark" | "vibrant" | "nature" | "urban" | Optional visual style |
direction body | string | Optional mood, motifs or references; the concept still comes from the cover |
feature_artist body | "auto" | "always" | "never" | Whether the Canvas shows the artist: auto (the director decides), always or never (AI sources; needs artist photos for "always") Default "auto". |
seconds body | integer 5–8 | Canvas length in whole seconds, 5–8 (default 8). Spotify loops it, so no part of the song is chosen Default 8. |
stock_id body | string | With a stock source: the Pexels photo or video (search_stock with seconds) to use instead of the director's pick |
quote_id body · required | uuid | The quote_id from the matching quote: the request must be identical |
List videos
GET /api/v1/videos
Videos, newest first, with status and thumbnails.
CLI kinetune videos list MCP list_videos Scopes videos:read
| Field | Type | Description |
|---|---|---|
song_id query | string | Only this song’s videos |
type query | "lyric-video" | "canvas" | — |
limit query | integer 1–100 | — |
Get a video
GET /api/v1/videos/{video_id}
Status, progress, credits and, when completed, the download links. status is queued, processing, completed, failed or cancelled. Completed videos have outputs with download_url (full quality), web_url (720p) and poster_url, signed for 7 days.
CLI kinetune videos get MCP get_video Scopes videos:read
| Field | Type | Description |
|---|---|---|
video_id path · required | string | The video id |
Cancel a video
POST /api/v1/videos/{video_id}/cancel
Stop a queued or processing video (credits released).
CLI kinetune videos cancel MCP cancel_video Scopes videos:write
| Field | Type | Description |
|---|---|---|
video_id path · required | string | The video id |
Make a video again
POST /api/v1/videos/{video_id}/retry
Run a finished, failed or cancelled video again (new charge). Reuses its Look, background media and loops, so nothing already made is paid for again.
CLI kinetune videos retry MCP retry_video Scopes videos:write
| Field | Type | Description |
|---|---|---|
video_id path · required | string | The video id |
Delete a video
DELETE /api/v1/videos/{video_id}
Delete a finished video and its files.
CLI kinetune videos delete MCP delete_video Scopes videos:write
| Field | Type | Description |
|---|---|---|
video_id path · required | string | The video id |