job_id you poll with
check_job.
Five are the workflows. Three are plumbing.
The five workflow tools take an optional
idempotency_key. On map_beats it replays the original
job. On the other four it only prevents a duplicate charge on a warm call, and it does nothing at
all on a cold one. See
what an Idempotency-Key does.
match_music
Match licensed music to a video. WrapsPOST /v1/match. Returns a ranked shortlist, each track
carrying a track_id you can pass to loop_music or get_sync_points.
string
A video you have already ingested. Provide this or
video_url.string
A public video URL. This ingests only, see the note below.
integer
default:"20"
A maximum, not a count. The shortlist is planned at 10 tracks, so any value above 10 still
returns at most 10. A smaller value slices the same ranked list.
string
A mood to steer the search, for example “uplifting” or “tense”.
string
A free-text brief for the vibe, for example “warm indie folk, no vocals”.
boolean
default:"false"
Embed sync points on every returned track. Cache-only, so see the note under
get_sync_points.
string
Advanced. Request a specific analysis engine. Clamped to your account’s tier, so leave it unset
to use your default.
Example call
Result
video_id whose analysis is not cached yet returns 202 with a job_id and a poll of
/v1/match/jobs/{job_id} instead. Poll it with check_job(job_id, "match").
underscore
Match licensed music to a script. No video needed. WrapsPOST /v1/underscore. Returns a ranked
shortlist, each track with its title, artist, tempo, its Soundstripe song id, and a match_map
showing which words pulled which sound. Synchronous, and billed flat per call. A call that comes
back with no tracks bills nothing. Like every Cue tool it returns identity and analysis, not audio.
string
required
The short-form script or copy to score. Up to 7000 characters.
string
Optional platform hint (
tiktok, reels, shorts, linkedin, youtube). Steers pace and
genre.string
A mood to steer the search.
string
A free-text brief for the vibe.
Example call
Result
video_id on this response. There was no video.
loop_music
Stretch a short track to cover a long video, as a downbeat-aligned, integer-bar self-loop with musical seams and fades that covers the whole clip. WrapsPOST /v1/loop. Soundstripe tracks only.
A video that is not long enough returns applicable: false and is not billed.
string
required
The long video to score.
string
required
A track to loop. This is the Soundstripe song id, so one from your own catalog works.
boolean
default:"false"
Also return a
mix block. If the video has a voiceover, this is how to sit the music under it.
Render mix.duck.envelope_points as attenuation on the music, interpolating linearly between
points. voiceover: false means there is nothing to duck. Adds no charge. Full recipe on
Loop, auto-mix.The first call for a given
(video_id, track_id) pair is cold. It returns {status: "processing", job_id, poll} and nothing else, and it bills the higher cold rate. Poll it with
check_job(job_id, "loop"). Every later call for that same pair returns the plan directly at the
low rate. A track you have already looped over one video is cold again on the next video.Example call
Result (warm)
plan.options, the full copies of every alternative, because they are
duplicates that would eat an agent’s context. plan.alternates carries a summary of each one
instead, in the same fields as the chosen plan. REST keeps options in full.
See Loop for how to read the plan and
Render loops under your own license for how to turn it into audio.
get_sync_points
Where to cut. Labeled sync offsets for one track against a video, best first. WrapsPOST /v1/align.
string
required
The video to align against.
string
required
A track from
match_music, or a Soundstripe song id you already hold.integer
default:"12"
How many sync points to return, up to 50. The response is a slice of one ranked list, so asking
for more gives you further down the same ranking.
boolean
default:"false"
Also return the
mix block, the same one loop_music returns. Adds no charge.A cold call returns
{status: "processing", job_id, poll} and bills the higher cold rate. Poll it
with check_job(job_id, "align"). Warm needs either the points for that exact (video_id, track_id) pair to be cached, or both profiles Cue would score them from: the video’s sync profile
and the track’s audio profile. The video’s profile is warmed in the background after ingest and
that warm is best-effort, so a track you have aligned many times can still come back cold on a new
video.Example call
Result (warm)
label names the musical moment the clip opens on, and it is one of Intro, Build, Peak,
Breakdown or Outro. It is "" for an ordinary mid-song moment, which is common, and null
when the energy fallback produced the point rather than the beat-sync engine. It is never “Drop”,
deliberately: a drop is a genre-specific event and most of the catalog does not have one, so the
biggest-energy moment is called Peak in every genre.
score orders this response and nothing else. Do not compare it across tracks.
map_beats
Map a track’s beats and downbeats. Send audio, get the grid. WrapsPOST /v1/beats.
string
required
An
https:// or s3:// URL to the audio. A presigned link from your own storage works.string
Your own identifier, echoed back on the job so you can reconcile a batch without keeping your own
job table.
number
Your catalog’s tempo, between 20 and 400. Worth a large accuracy gain when it is right. Pass it
only if you trust the octave, since a value at half or double the real tempo is worse than
nothing. Cue verifies it against its own reading and ignores it when the two disagree by an
octave.
string
The SHA-256 of the audio bytes, 64 hex characters. When this account has already mapped those
exact bytes, the job resolves from cache without fetching the file.
Example call
{ job_id, status: "processing", poll }. Poll with
check_job(job_id, "beats"). Billed per minute of audio, once, on success. A failed job bills
nothing.
Over MCP a long grid is summarised to its first 400 beats, because a full one would exceed the
tool-output limit and fail the call. When that happens the response sets beats_truncated: true,
carries beats_total and downbeats_total, and points at GET /v1/beats/{job_id}, which returns
all of it. See Map a track’s beats.
ingest_video
Add a video for reuse. WrapsPOST /v1/videos. Returns a video_id. Poll
check_video_status until it reads ready.
string
required
The URL to fetch. Anything Cue can
GET works, including a presigned link from your own storage,
so you do not have to make the file public.Example call
Result
check_video_status for it.
Holding the bytes locally instead? That is the REST upload flow.
POST /v1/videos with a
filename for a presigned upload URL, PUT the bytes, then POST /v1/videos/{video_id}/ingest to
start processing. It is not exposed over MCP on purpose, because the last step has no tool, so an
agent that started it here could never finish and would poll a video that never began processing.check_video_status
Is a videoprocessing, ready, or failed? Wraps GET /v1/videos/{id}. Never billed.
string
required
The video to check.
Result (ready)
Result (failed)
reason is populated only on failed and is prefixed with a token you can switch on. See
Errors & rate limits for the list.
check_job
Poll an async job returned bymatch_music, loop_music, get_sync_points or map_beats.
Returns processing until it is done, then the result. The job bills once, on completion, so
polling adds nothing and skipping it saves nothing.
string
required
The
job_id from the tool that returned status: "processing". A bare UUID, or 32 hex
characters for a beats job.string
default:"match"
Which job:
"match", "loop", "align" or "beats". Anything else is treated as "match".Example call
Result (still running)
Result (complete)
status: "failed"
result. Loop, sync and match jobs fail as 502. A beats job fails as 422, and so does one that
was never picked up, which was not billed and can simply be resubmitted.