curl --request POST \
--url https://app.goosybear.ai/api/v1/tools/shorts.write_beats \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"short_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"wants": "<string>",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workspace": "<string>"
}
'import requests
url = "https://app.goosybear.ai/api/v1/tools/shorts.write_beats"
payload = {
"short_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"wants": "<string>",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"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({
short_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
wants: '<string>',
confirmation_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
workspace: '<string>'
})
};
fetch('https://app.goosybear.ai/api/v1/tools/shorts.write_beats', 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/shorts.write_beats",
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([
'short_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'wants' => '<string>',
'confirmation_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'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/shorts.write_beats"
payload := strings.NewReader("{\n \"short_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"wants\": \"<string>\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\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/shorts.write_beats")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"short_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"wants\": \"<string>\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"workspace\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.goosybear.ai/api/v1/tools/shorts.write_beats")
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 \"short_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"wants\": \"<string>\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"workspace\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"workspace": "<string>",
"working_in": {
"label": "<string>",
"note": "<string>",
"workspace": "<string>",
"source": "call-override"
},
"state": "confirmation_required",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"expires_in_seconds": 123,
"request_summary": "<string>",
"short_id": "<string>",
"beats": [
{
"number": 123,
"name": "<string>",
"line": "<string>",
"seconds": 123,
"source": "you",
"layout": "<string>",
"budget": "<string>"
}
],
"seconds": 123,
"needs_filming": true,
"drawing_pictures": true,
"open_at": "<string>",
"questions": [
{
"key": "<string>",
"ask": "<string>",
"why": "<string>",
"example": "<string>"
}
],
"questions_note": "<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 shorts.write_beats
Deprecated: this name answers until 2027-02-12 as an alias of videos.write_script with kind “short”. Write the script of a video or a short from its plan — ‘write the script for this video’, ‘draft the script’, ‘scrap this script and start over for first-time founders’, ‘write the beats for this short’, ‘storyboard this short’. Send kind “video” with video_id, or “short” with short_id (leave it out for the short whose board they are on). Goosy writes it and the person reacts, so call it without asking them to write anything first. For a video it writes the script: use it for the first draft, and for a fresh draft from the plan when they want to start over; pass direction only for that fresh start, in their words. For a short it draws four to six beats with their full sheets, which are the short’s script and its storyboard in one act; call it as well when the person wants every beat drawn again, and pass wants only with something they said they want in the short. It answers in one of two ways. Started: the writing runs on its own job and the answer comes at once; say so in one line, with where it will land (a video’s Script step, a short’s storyboard) and that they can keep working meanwhile, and describe none of it, because none is written yet. Written: the call wrote a video’s script and the result carries the chapters; read them back rather than describing the script in general terms. Once a short’s beats are in, offer to write its shots. That written result may also carry questions: real facts the script needs that nobody has given (a name, the product, one number). Ask them as your very next turn, in your own words, in one message, and leave every answer to the person, because a made-up name ships in the finished video. This tool takes no answers, and calling it again before they are recorded writes a fresh script off the same unanswered brief. The script carries a blank everywhere an answer belongs, and a script or beats written on their job ask their questions where they land. Over the API it answers in two calls: without confirmation_id it proposes — says what would happen, returns a confirmation_id and changes, spends and sends nothing; the same arguments again with that confirmation_id, on a member’s own API key, do it.
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/shorts.write_beats \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"short_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"wants": "<string>",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"workspace": "<string>"
}
'import requests
url = "https://app.goosybear.ai/api/v1/tools/shorts.write_beats"
payload = {
"short_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"wants": "<string>",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"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({
short_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
wants: '<string>',
confirmation_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
workspace: '<string>'
})
};
fetch('https://app.goosybear.ai/api/v1/tools/shorts.write_beats', 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/shorts.write_beats",
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([
'short_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'wants' => '<string>',
'confirmation_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'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/shorts.write_beats"
payload := strings.NewReader("{\n \"short_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"wants\": \"<string>\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\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/shorts.write_beats")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"short_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"wants\": \"<string>\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"workspace\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.goosybear.ai/api/v1/tools/shorts.write_beats")
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 \"short_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"wants\": \"<string>\",\n \"confirmation_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"workspace\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"workspace": "<string>",
"working_in": {
"label": "<string>",
"note": "<string>",
"workspace": "<string>",
"source": "call-override"
},
"state": "confirmation_required",
"confirmation_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"expires_in_seconds": 123,
"request_summary": "<string>",
"short_id": "<string>",
"beats": [
{
"number": 123,
"name": "<string>",
"line": "<string>",
"seconds": 123,
"source": "you",
"layout": "<string>",
"budget": "<string>"
}
],
"seconds": 123,
"needs_filming": true,
"drawing_pictures": true,
"open_at": "<string>",
"questions": [
{
"key": "<string>",
"ask": "<string>",
"why": "<string>",
"example": "<string>"
}
],
"questions_note": "<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
Body
Omit to propose: the first call says what would happen, returns a confirmation_id and changes nothing. To go ahead, send the same arguments again with that confirmation_id, on a member's own API key; a service account's key can propose but never confirm.
^([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.