Skip to main content
A shortlist tells you which track. Sync tells you where. POST /v1/align takes one track and one video and returns labeled offsets into the song, best first: the drop, the downbeats, the phrase starts. These are the points where the music lands with what’s on screen. Use it for a clip the track can cover on its own. When the video is longer than the song, you want loop instead.

Align a track

200
offset_seconds is a position in the song: start the track there and it lines up with the top of your clip. score is how strongly that point lands, 0–1. label says what the moment is musically, and it is null on a track Cue could only align by energy. No match call is required. track_id is the Soundstripe song id, so you can align a track you picked yourself.
integer
default:"12"
How many sync points to return, 1–50.

A cold pairing comes back as a job

Cue serves the 200 above only from cache. When nothing is cached for this pairing, the index has to be built, and that takes longer than a request allows. So you get a 202 and a job:
202
Poll GET /v1/align/jobs/{job_id} until status is complete. The finished job returns the same sync_points, plus job_id, status and cached. A video whose ingest hasn’t finished gives you a different 202, with no job_id and a poll of /v1/videos/{video_id}. Poll the video to ready, then call /v1/align again.

Which answer you get, and what you pay

The warm read succeeds when either of these is true:
  • Cue has stored alignment points for this exact (video_id, track_id) pair, from an earlier align or from a background warm.
  • Both halves of the pairing are profiled: the video’s sync profile, built during ingest, and the track’s audio profile, built the first time that track is indexed for sync.
Miss both and you get the job and the cold rate. So the first align of a given track is normally cold, later aligns of that track against your other videos are normally warm, and the decision is made per call, per pairing, not once per track forever. cached on the response tells you which rate you paid.

Sync points on a match instead

If you want points for a whole shortlist rather than one track, pass "include_sync": true to /v1/match. That path is cache-only and never builds a profile, so on a fresh video most tracks come back "sync_status": "warming" with an empty sync_points array. /v1/align is the endpoint that actually builds the index. sync_status is one of warm (points included), warming (this pairing isn’t indexed yet, so call again shortly), unavailable (no points could be read) and error (something failed on our side, and the same call may succeed on a retry). unavailable and error used to be reported identically, which meant an outage read as a settled fact about your track.

Duck under voiceover

If the clip has narration, pass "auto_mix": true and the response carries a mix block: gains for the two beds, plus duck.envelope_points, the automation curve telling you how far to pull the music down at each instant. These are the same numbers the Cue app uses, so your render matches the app. It reads a measurement taken at ingest, so it adds no charge. When that measurement can’t be read, the 200 from POST /v1/align carries "mix": null and the completed job simply omits the key. Auto-mix is additive and never fails the align call, so treat null and absent the same way and check before you read into the block. The four-step render recipe and the full field-by-field description are on Loop. The block is identical on both endpoints.

What it costs

0.01foracoldpairing,0.01** for a cold pairing, **0.001 for a warm one. auto_mix adds nothing, and a call that errors bills nothing. Sync points embedded in a match are included in the match price. See Metering & pricing. Over MCP the same thing is the get_sync_points tool.