curl --request POST \
--url https://app.goosybear.ai/api/v1/tools/posts.save_variants \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"piece_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"variants": [
{
"platform": "<string>",
"caption": "<string>",
"description": "<string>",
"publish_at": "<string>",
"aspect_ratio": "<string>",
"hashtags": [
"<string>"
],
"alt_text": "<string>",
"first_comment": "<string>",
"location_label": "<string>",
"tagged_handles": [
"<string>"
],
"story": {
"frames": [
{
"text_sticker": "<string>",
"link_sticker_url": "<string>",
"link_sticker_label": "<string>",
"music_label": "<string>",
"alt_text": "<string>",
"poll": {
"question": "<string>",
"options": [
"<string>"
]
},
"mention_handles": [
"<string>"
],
"duration_seconds": 30
}
],
"expires_at": "<string>",
"highlight_name": "<string>"
}
}
],
"idempotency_key": "<string>",
"workspace": "<string>"
}
'import requests
url = "https://app.goosybear.ai/api/v1/tools/posts.save_variants"
payload = {
"piece_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"variants": [
{
"platform": "<string>",
"caption": "<string>",
"description": "<string>",
"publish_at": "<string>",
"aspect_ratio": "<string>",
"hashtags": ["<string>"],
"alt_text": "<string>",
"first_comment": "<string>",
"location_label": "<string>",
"tagged_handles": ["<string>"],
"story": {
"frames": [
{
"text_sticker": "<string>",
"link_sticker_url": "<string>",
"link_sticker_label": "<string>",
"music_label": "<string>",
"alt_text": "<string>",
"poll": {
"question": "<string>",
"options": ["<string>"]
},
"mention_handles": ["<string>"],
"duration_seconds": 30
}
],
"expires_at": "<string>",
"highlight_name": "<string>"
}
}
],
"idempotency_key": "<string>",
"workspace": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
piece_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
variants: [
{
platform: '<string>',
caption: '<string>',
description: '<string>',
publish_at: '<string>',
aspect_ratio: '<string>',
hashtags: ['<string>'],
alt_text: '<string>',
first_comment: '<string>',
location_label: '<string>',
tagged_handles: ['<string>'],
story: {
frames: [
{
text_sticker: '<string>',
link_sticker_url: '<string>',
link_sticker_label: '<string>',
music_label: '<string>',
alt_text: '<string>',
poll: {question: '<string>', options: ['<string>']},
mention_handles: ['<string>'],
duration_seconds: 30
}
],
expires_at: '<string>',
highlight_name: '<string>'
}
}
],
idempotency_key: '<string>',
workspace: '<string>'
})
};
fetch('https://app.goosybear.ai/api/v1/tools/posts.save_variants', 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/posts.save_variants",
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([
'piece_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'variants' => [
[
'platform' => '<string>',
'caption' => '<string>',
'description' => '<string>',
'publish_at' => '<string>',
'aspect_ratio' => '<string>',
'hashtags' => [
'<string>'
],
'alt_text' => '<string>',
'first_comment' => '<string>',
'location_label' => '<string>',
'tagged_handles' => [
'<string>'
],
'story' => [
'frames' => [
[
'text_sticker' => '<string>',
'link_sticker_url' => '<string>',
'link_sticker_label' => '<string>',
'music_label' => '<string>',
'alt_text' => '<string>',
'poll' => [
'question' => '<string>',
'options' => [
'<string>'
]
],
'mention_handles' => [
'<string>'
],
'duration_seconds' => 30
]
],
'expires_at' => '<string>',
'highlight_name' => '<string>'
]
]
],
'idempotency_key' => '<string>',
'workspace' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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/posts.save_variants"
payload := strings.NewReader("{\n \"piece_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"variants\": [\n {\n \"platform\": \"<string>\",\n \"caption\": \"<string>\",\n \"description\": \"<string>\",\n \"publish_at\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"hashtags\": [\n \"<string>\"\n ],\n \"alt_text\": \"<string>\",\n \"first_comment\": \"<string>\",\n \"location_label\": \"<string>\",\n \"tagged_handles\": [\n \"<string>\"\n ],\n \"story\": {\n \"frames\": [\n {\n \"text_sticker\": \"<string>\",\n \"link_sticker_url\": \"<string>\",\n \"link_sticker_label\": \"<string>\",\n \"music_label\": \"<string>\",\n \"alt_text\": \"<string>\",\n \"poll\": {\n \"question\": \"<string>\",\n \"options\": [\n \"<string>\"\n ]\n },\n \"mention_handles\": [\n \"<string>\"\n ],\n \"duration_seconds\": 30\n }\n ],\n \"expires_at\": \"<string>\",\n \"highlight_name\": \"<string>\"\n }\n }\n ],\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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/posts.save_variants")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"piece_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"variants\": [\n {\n \"platform\": \"<string>\",\n \"caption\": \"<string>\",\n \"description\": \"<string>\",\n \"publish_at\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"hashtags\": [\n \"<string>\"\n ],\n \"alt_text\": \"<string>\",\n \"first_comment\": \"<string>\",\n \"location_label\": \"<string>\",\n \"tagged_handles\": [\n \"<string>\"\n ],\n \"story\": {\n \"frames\": [\n {\n \"text_sticker\": \"<string>\",\n \"link_sticker_url\": \"<string>\",\n \"link_sticker_label\": \"<string>\",\n \"music_label\": \"<string>\",\n \"alt_text\": \"<string>\",\n \"poll\": {\n \"question\": \"<string>\",\n \"options\": [\n \"<string>\"\n ]\n },\n \"mention_handles\": [\n \"<string>\"\n ],\n \"duration_seconds\": 30\n }\n ],\n \"expires_at\": \"<string>\",\n \"highlight_name\": \"<string>\"\n }\n }\n ],\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.goosybear.ai/api/v1/tools/posts.save_variants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"piece_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"variants\": [\n {\n \"platform\": \"<string>\",\n \"caption\": \"<string>\",\n \"description\": \"<string>\",\n \"publish_at\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"hashtags\": [\n \"<string>\"\n ],\n \"alt_text\": \"<string>\",\n \"first_comment\": \"<string>\",\n \"location_label\": \"<string>\",\n \"tagged_handles\": [\n \"<string>\"\n ],\n \"story\": {\n \"frames\": [\n {\n \"text_sticker\": \"<string>\",\n \"link_sticker_url\": \"<string>\",\n \"link_sticker_label\": \"<string>\",\n \"music_label\": \"<string>\",\n \"alt_text\": \"<string>\",\n \"poll\": {\n \"question\": \"<string>\",\n \"options\": [\n \"<string>\"\n ]\n },\n \"mention_handles\": [\n \"<string>\"\n ],\n \"duration_seconds\": 30\n }\n ],\n \"expires_at\": \"<string>\",\n \"highlight_name\": \"<string>\"\n }\n }\n ],\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"piece_id": "<string>",
"saved": [
"<string>"
],
"refused": [
{
"platform": "<string>",
"code": "<string>",
"message": "<string>"
}
],
"replayed": true,
"workspace": "<string>",
"working_in": {
"label": "<string>",
"note": "<string>",
"workspace": "<string>",
"source": "call-override"
}
}{
"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 posts.save_variants
Save the version written for each destination of a post — ‘save these captions for Instagram and LinkedIn’, ‘here’s the LinkedIn version of this post’. It stores the words you send; it writes none itself. A destination must already be on the piece, each version must carry its words, and a destination that already published refuses, because its copy is the record of what went out. It saves the draft only; nothing is published. Not for the piece’s own copy — that is posts.fill_step.
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/posts.save_variants \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"piece_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"variants": [
{
"platform": "<string>",
"caption": "<string>",
"description": "<string>",
"publish_at": "<string>",
"aspect_ratio": "<string>",
"hashtags": [
"<string>"
],
"alt_text": "<string>",
"first_comment": "<string>",
"location_label": "<string>",
"tagged_handles": [
"<string>"
],
"story": {
"frames": [
{
"text_sticker": "<string>",
"link_sticker_url": "<string>",
"link_sticker_label": "<string>",
"music_label": "<string>",
"alt_text": "<string>",
"poll": {
"question": "<string>",
"options": [
"<string>"
]
},
"mention_handles": [
"<string>"
],
"duration_seconds": 30
}
],
"expires_at": "<string>",
"highlight_name": "<string>"
}
}
],
"idempotency_key": "<string>",
"workspace": "<string>"
}
'import requests
url = "https://app.goosybear.ai/api/v1/tools/posts.save_variants"
payload = {
"piece_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"variants": [
{
"platform": "<string>",
"caption": "<string>",
"description": "<string>",
"publish_at": "<string>",
"aspect_ratio": "<string>",
"hashtags": ["<string>"],
"alt_text": "<string>",
"first_comment": "<string>",
"location_label": "<string>",
"tagged_handles": ["<string>"],
"story": {
"frames": [
{
"text_sticker": "<string>",
"link_sticker_url": "<string>",
"link_sticker_label": "<string>",
"music_label": "<string>",
"alt_text": "<string>",
"poll": {
"question": "<string>",
"options": ["<string>"]
},
"mention_handles": ["<string>"],
"duration_seconds": 30
}
],
"expires_at": "<string>",
"highlight_name": "<string>"
}
}
],
"idempotency_key": "<string>",
"workspace": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
piece_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
variants: [
{
platform: '<string>',
caption: '<string>',
description: '<string>',
publish_at: '<string>',
aspect_ratio: '<string>',
hashtags: ['<string>'],
alt_text: '<string>',
first_comment: '<string>',
location_label: '<string>',
tagged_handles: ['<string>'],
story: {
frames: [
{
text_sticker: '<string>',
link_sticker_url: '<string>',
link_sticker_label: '<string>',
music_label: '<string>',
alt_text: '<string>',
poll: {question: '<string>', options: ['<string>']},
mention_handles: ['<string>'],
duration_seconds: 30
}
],
expires_at: '<string>',
highlight_name: '<string>'
}
}
],
idempotency_key: '<string>',
workspace: '<string>'
})
};
fetch('https://app.goosybear.ai/api/v1/tools/posts.save_variants', 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/posts.save_variants",
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([
'piece_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'variants' => [
[
'platform' => '<string>',
'caption' => '<string>',
'description' => '<string>',
'publish_at' => '<string>',
'aspect_ratio' => '<string>',
'hashtags' => [
'<string>'
],
'alt_text' => '<string>',
'first_comment' => '<string>',
'location_label' => '<string>',
'tagged_handles' => [
'<string>'
],
'story' => [
'frames' => [
[
'text_sticker' => '<string>',
'link_sticker_url' => '<string>',
'link_sticker_label' => '<string>',
'music_label' => '<string>',
'alt_text' => '<string>',
'poll' => [
'question' => '<string>',
'options' => [
'<string>'
]
],
'mention_handles' => [
'<string>'
],
'duration_seconds' => 30
]
],
'expires_at' => '<string>',
'highlight_name' => '<string>'
]
]
],
'idempotency_key' => '<string>',
'workspace' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$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/posts.save_variants"
payload := strings.NewReader("{\n \"piece_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"variants\": [\n {\n \"platform\": \"<string>\",\n \"caption\": \"<string>\",\n \"description\": \"<string>\",\n \"publish_at\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"hashtags\": [\n \"<string>\"\n ],\n \"alt_text\": \"<string>\",\n \"first_comment\": \"<string>\",\n \"location_label\": \"<string>\",\n \"tagged_handles\": [\n \"<string>\"\n ],\n \"story\": {\n \"frames\": [\n {\n \"text_sticker\": \"<string>\",\n \"link_sticker_url\": \"<string>\",\n \"link_sticker_label\": \"<string>\",\n \"music_label\": \"<string>\",\n \"alt_text\": \"<string>\",\n \"poll\": {\n \"question\": \"<string>\",\n \"options\": [\n \"<string>\"\n ]\n },\n \"mention_handles\": [\n \"<string>\"\n ],\n \"duration_seconds\": 30\n }\n ],\n \"expires_at\": \"<string>\",\n \"highlight_name\": \"<string>\"\n }\n }\n ],\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
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/posts.save_variants")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"piece_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"variants\": [\n {\n \"platform\": \"<string>\",\n \"caption\": \"<string>\",\n \"description\": \"<string>\",\n \"publish_at\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"hashtags\": [\n \"<string>\"\n ],\n \"alt_text\": \"<string>\",\n \"first_comment\": \"<string>\",\n \"location_label\": \"<string>\",\n \"tagged_handles\": [\n \"<string>\"\n ],\n \"story\": {\n \"frames\": [\n {\n \"text_sticker\": \"<string>\",\n \"link_sticker_url\": \"<string>\",\n \"link_sticker_label\": \"<string>\",\n \"music_label\": \"<string>\",\n \"alt_text\": \"<string>\",\n \"poll\": {\n \"question\": \"<string>\",\n \"options\": [\n \"<string>\"\n ]\n },\n \"mention_handles\": [\n \"<string>\"\n ],\n \"duration_seconds\": 30\n }\n ],\n \"expires_at\": \"<string>\",\n \"highlight_name\": \"<string>\"\n }\n }\n ],\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.goosybear.ai/api/v1/tools/posts.save_variants")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"piece_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"variants\": [\n {\n \"platform\": \"<string>\",\n \"caption\": \"<string>\",\n \"description\": \"<string>\",\n \"publish_at\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"hashtags\": [\n \"<string>\"\n ],\n \"alt_text\": \"<string>\",\n \"first_comment\": \"<string>\",\n \"location_label\": \"<string>\",\n \"tagged_handles\": [\n \"<string>\"\n ],\n \"story\": {\n \"frames\": [\n {\n \"text_sticker\": \"<string>\",\n \"link_sticker_url\": \"<string>\",\n \"link_sticker_label\": \"<string>\",\n \"music_label\": \"<string>\",\n \"alt_text\": \"<string>\",\n \"poll\": {\n \"question\": \"<string>\",\n \"options\": [\n \"<string>\"\n ]\n },\n \"mention_handles\": [\n \"<string>\"\n ],\n \"duration_seconds\": 30\n }\n ],\n \"expires_at\": \"<string>\",\n \"highlight_name\": \"<string>\"\n }\n }\n ],\n \"idempotency_key\": \"<string>\",\n \"workspace\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"piece_id": "<string>",
"saved": [
"<string>"
],
"refused": [
{
"platform": "<string>",
"code": "<string>",
"message": "<string>"
}
],
"replayed": true,
"workspace": "<string>",
"working_in": {
"label": "<string>",
"note": "<string>",
"workspace": "<string>",
"source": "call-override"
}
}{
"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; this action needs a key on one of the two, and the header is the one to send.
200Body
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.