curl --request POST \
--url https://app.goosybear.ai/api/v1/tools/videos.generate_clip \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"video_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"scene_id": "<string>",
"shows": "<string>",
"seconds": 5,
"tier": "standard",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"idempotency_key": "<string>",
"workspace": "<string>"
}
'import requests
url = "https://app.goosybear.ai/api/v1/tools/videos.generate_clip"
payload = {
"video_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"scene_id": "<string>",
"shows": "<string>",
"seconds": 5,
"tier": "standard",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"idempotency_key": "<string>",
"workspace": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
video_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
scene_id: '<string>',
shows: '<string>',
seconds: 5,
tier: 'standard',
confirmation_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
idempotency_key: '<string>',
workspace: '<string>'
})
};
fetch('https://app.goosybear.ai/api/v1/tools/videos.generate_clip', 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://app.goosybear.ai/api/v1/tools/videos.generate_clip",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'video_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'scene_id' => '<string>',
'shows' => '<string>',
'seconds' => 5,
'tier' => 'standard',
'confirmation_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'idempotency_key' => '<string>',
'workspace' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.goosybear.ai/api/v1/tools/videos.generate_clip"
payload := strings.NewReader("{\n \"video_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"scene_id\": \"<string>\",\n \"shows\": \"<string>\",\n \"seconds\": 5,\n \"tier\": \"standard\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.goosybear.ai/api/v1/tools/videos.generate_clip")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"video_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"scene_id\": \"<string>\",\n \"shows\": \"<string>\",\n \"seconds\": 5,\n \"tier\": \"standard\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.goosybear.ai/api/v1/tools/videos.generate_clip")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"video_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"scene_id\": \"<string>\",\n \"shows\": \"<string>\",\n \"seconds\": 5,\n \"tier\": \"standard\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"state": "confirmation_required",
"workspace": "<string>",
"working_in": {
"label": "<string>",
"note": "<string>",
"workspace": "<string>",
"source": "call-override"
},
"video_id": "<string>",
"scene_id": "<string>",
"seconds": 123,
"marker": "<string>",
"open_at": "<string>",
"job_id": "<string>",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"expires_in_seconds": 123,
"request_summary": "<string>"
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}Call videos.generate_clip
‘generate a clip for this scene’, ‘put real footage of a busy kitchen in scene two’ — start a made clip for one storyboard scene, and return its job handle. A real-world or filmed-looking shot is made too: there is no stock library. The clip is NOT ready when this answers; follow its job_id with jobs.read. A retry carrying the same idempotency_key returns the same clip, never a second one. tier sets the quality and the price per second: ‘lite’ costs least, ‘standard’ is the default, ‘quality’ looks best and costs the most. This is PAID generation and needs the key holder to be a workspace admin: on a member’s own key it starts in one call; on a key with no member behind it the first call describes the clip, charges nothing and returns a confirmation id, and the second, carrying that id back, is what starts it. Not for drawing the whole storyboard — that is videos.draw_storyboard.
Every result names the workspace it ran in. Say which workspace the answer is about. When the account has more than one workspace and none is selected, this tool refuses with workspace_ambiguous and lists the choices — offer them, never pick one.
curl --request POST \
--url https://app.goosybear.ai/api/v1/tools/videos.generate_clip \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"video_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"scene_id": "<string>",
"shows": "<string>",
"seconds": 5,
"tier": "standard",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"idempotency_key": "<string>",
"workspace": "<string>"
}
'import requests
url = "https://app.goosybear.ai/api/v1/tools/videos.generate_clip"
payload = {
"video_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"scene_id": "<string>",
"shows": "<string>",
"seconds": 5,
"tier": "standard",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"idempotency_key": "<string>",
"workspace": "<string>"
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
video_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
scene_id: '<string>',
shows: '<string>',
seconds: 5,
tier: 'standard',
confirmation_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
idempotency_key: '<string>',
workspace: '<string>'
})
};
fetch('https://app.goosybear.ai/api/v1/tools/videos.generate_clip', 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://app.goosybear.ai/api/v1/tools/videos.generate_clip",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'video_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'scene_id' => '<string>',
'shows' => '<string>',
'seconds' => 5,
'tier' => 'standard',
'confirmation_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'idempotency_key' => '<string>',
'workspace' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.goosybear.ai/api/v1/tools/videos.generate_clip"
payload := strings.NewReader("{\n \"video_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"scene_id\": \"<string>\",\n \"shows\": \"<string>\",\n \"seconds\": 5,\n \"tier\": \"standard\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.goosybear.ai/api/v1/tools/videos.generate_clip")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"video_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"scene_id\": \"<string>\",\n \"shows\": \"<string>\",\n \"seconds\": 5,\n \"tier\": \"standard\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.goosybear.ai/api/v1/tools/videos.generate_clip")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"video_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"scene_id\": \"<string>\",\n \"shows\": \"<string>\",\n \"seconds\": 5,\n \"tier\": \"standard\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"state": "confirmation_required",
"workspace": "<string>",
"working_in": {
"label": "<string>",
"note": "<string>",
"workspace": "<string>",
"source": "call-override"
},
"video_id": "<string>",
"scene_id": "<string>",
"seconds": 123,
"marker": "<string>",
"open_at": "<string>",
"job_id": "<string>",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"expires_in_seconds": 123,
"request_summary": "<string>"
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}{
"ok": false,
"code": "<string>",
"message": "<string>",
"error": {
"code": "<string>",
"message": "<string>",
"retry_after_seconds": 123
},
"retry_after_seconds": 123
}Authorizations
An API key minted at Settings › API & MCP. Send it as Authorization: Bearer <key>. A key carries its holder's own permissions, resolved on every call — revoking a membership closes the key's reach immediately. Keep it in an environment variable (GOOSY_API_KEY), never in a committed file.
Headers
Your key for this write: send the same key when you retry and the first result comes back instead of a second action. Keys are honoured for at least 24 hours. 1–200 visible ASCII characters. Replaces the idempotency_key body field, which still works until 2026-12-31.
200Body
How good the clip looks, which sets what it costs: 'lite' costs least and looks plainest, 'standard' suits most clips, 'quality' looks best and costs the most. Use the person's pick, or what fits the budget they named; leave it out and the clip is 'standard'.
lite, standard, quality Only when a first call answered confirmation_required: send that id back, unchanged, to run the recorded request. On your own member key the first call already runs, and there is no id.
^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})$Response
The call was admitted and dispatched. ok says whether the tool succeeded — a refusal the tool itself produced is still a 200, exactly as it is a successful JSON-RPC result over MCP.
- Option 1
- Option 2
The tool ran and answered.