Music Library
Licensed Artlist tracks your agent can pull into a video, with BPM, beat grid, and hook timing included so cuts land on the beat.
Every video needs music, and the rule is simple: real licensed Artlist tracks, never AI-generated. Before this existed, that meant downloading a track by hand before every render. The music library turns that into three MCP tool calls, with BPM, a beat grid, and a hook start computed once so scene timing can snap to the beat instead of guessing.
How a track gets in
Upload a file you already own. Upload an MP3 or WAV the same way you'd upload any other media asset — get_media_upload_url → PUT the bytes → finalize_media_upload. On finalize, the library reads the file's duration. Then create the music-library entry:
POST /api/v2/music-tracks
{ "asset_id": "<the finalized asset id>", "artist": "Evert Z", "mood": ["gritty"], "genre": ["western"] }
This is also where BPM, the beat grid, and the hook start get computed — once, at creation time, never recomputed on a read.
Import directly from Artlist. If the site has an Artlist Enterprise API key configured (Settings → Integrations), skip the manual download:
POST /api/v2/music-tracks/import-artlist
{ "song_id_or_url": "https://artlist.io/royalty-free-music/song/outlaws-of-the-old-west/12345" }
This calls Artlist's Enterprise API directly, downloads the licensed file, stores it, and analyzes it the same way as a manual upload. No Artlist key? The upload path above works with no setup at all — the Artlist import is a convenience, not a requirement.
The Artlist credential
Settings → Integrations → Artlist. The key is encrypted at rest (AES-256-GCM, the same scheme as the GA4/GSC service account credentials) and is never returned by any API response, MCP tool response, or log line — the settings page only ever shows whether a key is configured, never the key itself.
MCP tools
| Tool | What it does |
|---|---|
list_music_tracks | Filter by mood, genre, and BPM range. Excludes tracks used in the site's most recent videos by default (the "vary the track" rule) — pass exclude_recent: false to see everything. |
get_music_track | One track's full detail: download_url (null until a file is uploaded), bpm, beat_grid_sec, downbeats_sec, hook_start_seconds, duration_seconds. |
mark_music_used | Record that a track was used in a video, so the next list_music_tracks call excludes it for a while. Call this once the video is actually rendered — not at pick time, in case the pick changes. |
The intended order: list_music_tracks to pick a candidate → get_music_track to lock in its beat grid and hook → write scene code that snaps cuts to downbeats_sec and opens any short cut at hook_start_seconds → mark_music_used once the render is final.
Beat grid and hook, explained
bpm— the track's tempo, detected from the audio itself (not just whatever Artlist's catalog metadata says).beat_grid_sec— every detected beat, in seconds from the start of the track.downbeats_sec— every 4th beat (4/4 time assumed), i.e. the start of each bar. Snap scene/cut durations to these so a cut lands on a bar line instead of mid-beat.hook_start_seconds— the track's highest-energy moment, snapped to the nearest downbeat. Start a short cut here instead of at 0:00.
A note on the download URL
download_url (from get_music_track, or on the image_assets row) is a storage URL, not a signed or expiring one — reachable by anyone who has it, the same as every other asset in the media library. That's an acceptable risk for a hero image; licensed Artlist audio carries real licensing terms, so treat the URL as something to use server-side (download, mux into the render) rather than something to hand to a third party or publish directly.
Seeded tracks
The library ships seeded with four tracks from Evert Z's "Roll with the Punches" album — Why We Ride, Outlaws of the Old West, Southern Renegade, and Restless Rebels — with title, artist, and BPM filled in, status: "needs_audio", and no file yet. Upload the actual audio (or import it from Artlist) to move a seeded entry to status: "ready" and unlock its beat grid and download_url.