curl --request GET \
--url https://cue.vibeset.ai/v1/loop/jobs/{job_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://cue.vibeset.ai/v1/loop/jobs/{job_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://cue.vibeset.ai/v1/loop/jobs/{job_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://cue.vibeset.ai/v1/loop/jobs/{job_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://cue.vibeset.ai/v1/loop/jobs/{job_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://cue.vibeset.ai/v1/loop/jobs/{job_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://cue.vibeset.ai/v1/loop/jobs/{job_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"video_id": "<string>",
"track_id": "<string>",
"track": {
"soundstripe_song_id": "<string>",
"soundstripe_audio_file_id": "<string>"
},
"applicable": true,
"plan": {
"applicable": true,
"reason": "<string>",
"video_seconds": 123,
"track_seconds": 123,
"required_excess_seconds": 123,
"version": 123,
"segments": [
{
"song_from": 123,
"song_to": 123,
"gain_db": 123,
"gain_in_db": 123
}
],
"seam_fades": [
123
],
"seam_curves": [
123
],
"gain_glide_seconds": 123,
"music_in": 123,
"music_out": 123,
"window_end": 123,
"music_end": 123,
"tail_seconds": 123,
"song_start": 123,
"song_duration": 123,
"loop_start_a": 123,
"loop_end_b": 123,
"bars": 123,
"beats_per_bar": 123,
"repeats": 123,
"seam_score": 123,
"seam_times": [
123
],
"sections_covered": [
"<string>"
],
"end_label": "<string>",
"outro_start": 123,
"outro_end": 123,
"start_fade_seconds": 123,
"end_fade_seconds": 123,
"plan_score": 123,
"options": [
{}
],
"alternates": [
{}
]
},
"hint": "<string>",
"retryable": true,
"mix": {
"voiceover": true,
"classification": "voice",
"music_gain_db": -4.4,
"video_gain_db": 11.4,
"duck": {
"envelope_points": [
[
0,
20
],
[
1.2,
20
],
[
1.9,
0
],
[
4.8,
0
]
],
"envelope_hz": 40,
"speech_ranges": [
[
1.2,
4.8
],
[
9.5,
14.1
]
],
"depth_db": 20,
"attack_ms": 375,
"release_ms": 1425
}
},
"job_id": "<string>",
"status": "complete",
"cached": true
}{
"video_id": "<string>",
"track_id": "<string>",
"job_id": "<string>",
"status": "processing",
"poll": "/v1/loop/jobs/run_9f2c",
"next": "<string>"
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}Poll a loop job
Poll a loop job returned by POST /v1/loop. 202 while running. 200 with the loop
plan once complete, plus job_id, status and cached. Billed once, on completion, and
not billed at all when the result is applicable: false.
curl --request GET \
--url https://cue.vibeset.ai/v1/loop/jobs/{job_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://cue.vibeset.ai/v1/loop/jobs/{job_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://cue.vibeset.ai/v1/loop/jobs/{job_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://cue.vibeset.ai/v1/loop/jobs/{job_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://cue.vibeset.ai/v1/loop/jobs/{job_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://cue.vibeset.ai/v1/loop/jobs/{job_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://cue.vibeset.ai/v1/loop/jobs/{job_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"video_id": "<string>",
"track_id": "<string>",
"track": {
"soundstripe_song_id": "<string>",
"soundstripe_audio_file_id": "<string>"
},
"applicable": true,
"plan": {
"applicable": true,
"reason": "<string>",
"video_seconds": 123,
"track_seconds": 123,
"required_excess_seconds": 123,
"version": 123,
"segments": [
{
"song_from": 123,
"song_to": 123,
"gain_db": 123,
"gain_in_db": 123
}
],
"seam_fades": [
123
],
"seam_curves": [
123
],
"gain_glide_seconds": 123,
"music_in": 123,
"music_out": 123,
"window_end": 123,
"music_end": 123,
"tail_seconds": 123,
"song_start": 123,
"song_duration": 123,
"loop_start_a": 123,
"loop_end_b": 123,
"bars": 123,
"beats_per_bar": 123,
"repeats": 123,
"seam_score": 123,
"seam_times": [
123
],
"sections_covered": [
"<string>"
],
"end_label": "<string>",
"outro_start": 123,
"outro_end": 123,
"start_fade_seconds": 123,
"end_fade_seconds": 123,
"plan_score": 123,
"options": [
{}
],
"alternates": [
{}
]
},
"hint": "<string>",
"retryable": true,
"mix": {
"voiceover": true,
"classification": "voice",
"music_gain_db": -4.4,
"video_gain_db": 11.4,
"duck": {
"envelope_points": [
[
0,
20
],
[
1.2,
20
],
[
1.9,
0
],
[
4.8,
0
]
],
"envelope_hz": 40,
"speech_ranges": [
[
1.2,
4.8
],
[
9.5,
14.1
]
],
"depth_db": 20,
"attack_ms": 375,
"release_ms": 1425
}
},
"job_id": "<string>",
"status": "complete",
"cached": true
}{
"video_id": "<string>",
"track_id": "<string>",
"job_id": "<string>",
"status": "processing",
"poll": "/v1/loop/jobs/run_9f2c",
"next": "<string>"
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}{
"error": {
"type": "invalid_request",
"message": "Provide either 'video_id' or 'video_url'.",
"request_id": "a1b2c3d4e5f6"
}
}Authorizations
Your API key as a Bearer token, e.g. Authorization: Bearer vbsk_live_...
Path Parameters
Response
The finished loop plan.
A completed loop job, a LoopResult plus the job's own fields.
The catalog identifiers for the recording a loop plan describes. The song is the work, the audio file is the specific render you fetch. They are not interchangeable.
Show child attributes
Show child attributes
How to lay the track under the clip. segments is the authoritative playback path. loop_start_a / loop_end_b / repeats describe the same loop but cannot express a final pass that exits into a come-down outro. On a not-applicable result only applicable, reason and (for video_not_longer) the three duration fields are present.
Show child attributes
Show child attributes
Auto-mix (duck-the-music-under-the-voiceover) spec, returned when auto_mix is true. These are the same numbers the Cue app's Loop/Sync preview + export use, so a render with them matches the app. Applicable to whatever music you lay under the clip.
Show child attributes
Show child attributes
{
"voiceover": true,
"classification": "voice",
"music_gain_db": -4.4,
"video_gain_db": 11.4,
"duck": {
"envelope_points": [[0, 20], [1.2, 20], [1.9, 0], [4.8, 0]],
"envelope_hz": 40,
"speech_ranges": [[1.2, 4.8], [9.5, 14.1]],
"depth_db": 20,
"attack_ms": 375,
"release_ms": 1425
}
}
complete