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

  1. Add a song: the master audio and its square cover art. It is analyzed (lyrics, beats, sections) in about a minute.
  2. Quote the video you want. The quote is the exact number of credits; nothing is charged.
  3. Create it with the same request plus the quote_id. Credits are held, and charged only when the video is delivered.
  4. Wait for status: "completed": poll the video or receive a signed callback.
  5. 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.

  1. In ChatGPT, open Settings → Apps & Connectors → Advanced and turn on Developer mode (it depends on your plan and workspace settings).
  2. Choose Create, name it Kinetune, paste the server URL and pick OAuth.
  3. 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.

ToolWhat it does
get_accountWho you are signed in as, the organization and its credit balance
get_optionsVideo types, Look categories, background sources, formats and the current credit prices
list_artistsArtists by name, with their song and photo counts and a picture
create_artistAdd an artist by name
get_artistOne artist
rename_artistChange an artist’s name
archive_artist destructiveRemove an artist that has no songs
set_artist_pictureChoose which photo is the artist’s picture, and how it is cropped to a square
list_artist_photosThe artist’s photos (identity references, up to 6)
add_artist_photosUpload one or more photos of the artist (JPEG, PNG or WebP)
delete_artist_photo destructiveRemove one photo
list_songsSongs with their cover, duration and analysis status
create_songAdd a song: master audio and square cover art
get_songOne song and its analysis status
rename_songChange a song’s title
archive_song destructiveRemove a song (its videos stay)
get_song_analysisWord-timed lyrics, tempo, beats, sections and hook
reanalyze_songRetry a failed analysis
list_looksBrowse Official, Community and your own Looks
get_lookOne Look with its design and preview images
rename_lookRename one of your Looks
delete_look destructiveRemove one of your Looks (videos made with it stay)
set_look_visibilityMake one of your Looks public (earns 10 credits) or private
upload_backgroundUpload your own photo or video to design a New Look around
search_stockFind Pexels photos or clips to use as a stock background
quote_lyric_videoThe exact credits for a lyric video, before anything is charged
quote_canvasThe exact credits for a Spotify Canvas, before anything is charged
create_lyric_videoMake the lyric video a quote priced (spends credits)
create_canvasMake the Canvas a quote priced (spends credits)
list_videosVideos, newest first, with status and thumbnails
get_videoStatus, progress, credits and, when completed, the download links
cancel_video destructiveStop a queued or processing video (credits released)
retry_videoRun a finished, failed or cancelled video again (new charge)
delete_video destructiveDelete a finished video and its files
wait_for_videoWaits 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.

  1. In a self-hosted n8n, open Settings → Community nodes → Install and enter @kinetune/n8n-nodes-kinetune.
  2. Create a Kinetune API credential with an API key from the app; the base URL is https://kinetune.com.
  3. 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.
  4. 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

FieldTypeDescription
q querystringPart of the artist name
limit queryinteger 1–100Results per page, 1-100 (default 50)
offset queryinteger 0–9007199254740991How 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

FieldTypeDescription
name body · requiredstringThe 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

FieldTypeDescription
artist_id path · requiredstringThe 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

FieldTypeDescription
artist_id path · requiredstringThe artist id
name body · requiredstringThe 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

FieldTypeDescription
artist_id path · requiredstringThe 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

FieldTypeDescription
artist_id path · requiredstringThe artist id
photo_id body · requiredstringOne of the artist’s photos (list_artist_photos)
crop bodyobjectThe 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

FieldTypeDescription
artist_id path · requiredstringThe 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).

FieldTypeDescription
artist_id path · requiredstringThe artist id
photo_urls bodyURL[] (1–6)Public https URLs of the photos (or upload files with the CLI)
rights_confirmed body · requiredtrueYou 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

FieldTypeDescription
artist_id path · requiredstringThe artist id
photo_id path · requiredstringThe 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

FieldTypeDescription
artist_id querystringOnly this artist’s songs
q querystringPart of the song title or artist name
limit queryinteger 1–100Results per page, 1-100 (default 50)
offset queryinteger 0–9007199254740991How 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).

FieldTypeDescription
artist_id body · requiredstringThe artist id
title body · requiredstringThe song title
language bodystringLyrics language (ISO 639-1, e.g. "en"); detected when omitted
audio_url bodyURLA public https URL of the master audio
cover_art_url bodyURLA 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

FieldTypeDescription
song_id path · requiredstringThe 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

FieldTypeDescription
song_id path · requiredstringThe song id
title body · requiredstringThe 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

FieldTypeDescription
song_id path · requiredstringThe 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

FieldTypeDescription
song_id path · requiredstringThe 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

FieldTypeDescription
song_id path · requiredstringThe 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

FieldTypeDescription
scope query"all" | "official" | "community" | "mine"Which library; default all
category querystringA category id from get_options
lyric_style querystringA lyric style id from get_options (how the lyrics move)
artist_id querystringThe artist of the song you are choosing for: Looks that show another artist are left out
q querystringSearch words
sort query"newest" | "popular"—
limit queryinteger 1–100—
offset queryinteger 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

FieldTypeDescription
look_id path · requiredstringThe 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

FieldTypeDescription
look_id path · requiredstringThe Look id
name body · requiredstringThe 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

FieldTypeDescription
look_id path · requiredstringThe 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

FieldTypeDescription
look_id path · requiredstringThe 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).

FieldTypeDescription
file_url bodyURLA public https URL of the photo or video
rights_confirmed body · requiredtrueYou 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

FieldTypeDescription
song_id body · requiredstringThe song id
variations bodyinteger 1–41–4 different New Looks, one video each (an Existing Look renders one) Default 1.
callback_url bodystringAn https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value
metadata bodyobjectYour 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 · requiredobject{"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 bodyobjectWhich 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 bodyobjectRender 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

FieldTypeDescription
song_id body · requiredstringThe song id
variations bodyinteger 1–41–4 different Canvases Default 1.
callback_url bodystringAn https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value
metadata bodyobjectYour 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 bodystringOptional 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 bodyinteger 5–8Canvas length in whole seconds, 5–8 (default 8). Spotify loops it, so no part of the song is chosen Default 8.
stock_id bodystringWith 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

FieldTypeDescription
song_id body · requiredstringThe song id
variations bodyinteger 1–41–4 different New Looks, one video each (an Existing Look renders one) Default 1.
callback_url bodystringAn https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value
metadata bodyobjectYour 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 · requiredobject{"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 bodyobjectWhich 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 bodyobjectRender only this section of the song (at least 8 seconds)
quote_id body · requireduuidThe 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

FieldTypeDescription
song_id body · requiredstringThe song id
variations bodyinteger 1–41–4 different Canvases Default 1.
callback_url bodystringAn https URL to POST the finished video to (signed; see Callbacks). Quote and create with the same value
metadata bodyobjectYour 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 bodystringOptional 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 bodyinteger 5–8Canvas length in whole seconds, 5–8 (default 8). Spotify loops it, so no part of the song is chosen Default 8.
stock_id bodystringWith a stock source: the Pexels photo or video (search_stock with seconds) to use instead of the director's pick
quote_id body · requireduuidThe 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

FieldTypeDescription
song_id querystringOnly this song’s videos
type query"lyric-video" | "canvas"—
limit queryinteger 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

FieldTypeDescription
video_id path · requiredstringThe 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

FieldTypeDescription
video_id path · requiredstringThe 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

FieldTypeDescription
video_id path · requiredstringThe 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

FieldTypeDescription
video_id path · requiredstringThe video id