Generate Slideshow
curl --request POST \
--url https://api.example.com/api/partner/v1/slideshows/generate \
--header 'Content-Type: application/json' \
--data '
{
"prompt": "<string>",
"product_id": {},
"pack_id": {},
"image_sourcing": "<string>",
"slide_count": 123,
"slideshow_type": "<string>",
"aspect_ratio": "<string>",
"language": "<string>",
"advanced_settings": {
"font_size": {},
"text_preset": "<string>",
"text_width": "<string>"
},
"skip_ai": true,
"slide_config": {
"total_slides": 123,
"slide_types": [
{}
],
"custom_images": {},
"pinned_images": {},
"slide_texts": {},
"slide_text_elements": {},
"pack_assignments": {}
}
}
'import requests
url = "https://api.example.com/api/partner/v1/slideshows/generate"
payload = {
"prompt": "<string>",
"product_id": {},
"pack_id": {},
"image_sourcing": "<string>",
"slide_count": 123,
"slideshow_type": "<string>",
"aspect_ratio": "<string>",
"language": "<string>",
"advanced_settings": {
"font_size": {},
"text_preset": "<string>",
"text_width": "<string>"
},
"skip_ai": True,
"slide_config": {
"total_slides": 123,
"slide_types": [{}],
"custom_images": {},
"pinned_images": {},
"slide_texts": {},
"slide_text_elements": {},
"pack_assignments": {}
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
prompt: '<string>',
product_id: {},
pack_id: {},
image_sourcing: '<string>',
slide_count: 123,
slideshow_type: '<string>',
aspect_ratio: '<string>',
language: '<string>',
advanced_settings: {font_size: {}, text_preset: '<string>', text_width: '<string>'},
skip_ai: true,
slide_config: {
total_slides: 123,
slide_types: [{}],
custom_images: {},
pinned_images: {},
slide_texts: {},
slide_text_elements: {},
pack_assignments: {}
}
})
};
fetch('https://api.example.com/api/partner/v1/slideshows/generate', 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://api.example.com/api/partner/v1/slideshows/generate",
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([
'prompt' => '<string>',
'product_id' => [
],
'pack_id' => [
],
'image_sourcing' => '<string>',
'slide_count' => 123,
'slideshow_type' => '<string>',
'aspect_ratio' => '<string>',
'language' => '<string>',
'advanced_settings' => [
'font_size' => [
],
'text_preset' => '<string>',
'text_width' => '<string>'
],
'skip_ai' => true,
'slide_config' => [
'total_slides' => 123,
'slide_types' => [
[
]
],
'custom_images' => [
],
'pinned_images' => [
],
'slide_texts' => [
],
'slide_text_elements' => [
],
'pack_assignments' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"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://api.example.com/api/partner/v1/slideshows/generate"
payload := strings.NewReader("{\n \"prompt\": \"<string>\",\n \"product_id\": {},\n \"pack_id\": {},\n \"image_sourcing\": \"<string>\",\n \"slide_count\": 123,\n \"slideshow_type\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"language\": \"<string>\",\n \"advanced_settings\": {\n \"font_size\": {},\n \"text_preset\": \"<string>\",\n \"text_width\": \"<string>\"\n },\n \"skip_ai\": true,\n \"slide_config\": {\n \"total_slides\": 123,\n \"slide_types\": [\n {}\n ],\n \"custom_images\": {},\n \"pinned_images\": {},\n \"slide_texts\": {},\n \"slide_text_elements\": {},\n \"pack_assignments\": {}\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
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://api.example.com/api/partner/v1/slideshows/generate")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"<string>\",\n \"product_id\": {},\n \"pack_id\": {},\n \"image_sourcing\": \"<string>\",\n \"slide_count\": 123,\n \"slideshow_type\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"language\": \"<string>\",\n \"advanced_settings\": {\n \"font_size\": {},\n \"text_preset\": \"<string>\",\n \"text_width\": \"<string>\"\n },\n \"skip_ai\": true,\n \"slide_config\": {\n \"total_slides\": 123,\n \"slide_types\": [\n {}\n ],\n \"custom_images\": {},\n \"pinned_images\": {},\n \"slide_texts\": {},\n \"slide_text_elements\": {},\n \"pack_assignments\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/partner/v1/slideshows/generate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"<string>\",\n \"product_id\": {},\n \"pack_id\": {},\n \"image_sourcing\": \"<string>\",\n \"slide_count\": 123,\n \"slideshow_type\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"language\": \"<string>\",\n \"advanced_settings\": {\n \"font_size\": {},\n \"text_preset\": \"<string>\",\n \"text_width\": \"<string>\"\n },\n \"skip_ai\": true,\n \"slide_config\": {\n \"total_slides\": 123,\n \"slide_types\": [\n {}\n ],\n \"custom_images\": {},\n \"pinned_images\": {},\n \"slide_texts\": {},\n \"slide_text_elements\": {},\n \"pack_assignments\": {}\n }\n}"
response = http.request(request)
puts response.read_bodySlideshows
Generate Slideshow
Generate AI-powered slideshows for TikTok photo carousels, Instagram carousels, Pinterest pins, and more. Supports AI generation from prompts, manual slide configuration, and mixed mode. The core content creation endpoint for OpenClaw agents.
POST
/
api
/
partner
/
v1
/
slideshows
/
generate
Generate Slideshow
curl --request POST \
--url https://api.example.com/api/partner/v1/slideshows/generate \
--header 'Content-Type: application/json' \
--data '
{
"prompt": "<string>",
"product_id": {},
"pack_id": {},
"image_sourcing": "<string>",
"slide_count": 123,
"slideshow_type": "<string>",
"aspect_ratio": "<string>",
"language": "<string>",
"advanced_settings": {
"font_size": {},
"text_preset": "<string>",
"text_width": "<string>"
},
"skip_ai": true,
"slide_config": {
"total_slides": 123,
"slide_types": [
{}
],
"custom_images": {},
"pinned_images": {},
"slide_texts": {},
"slide_text_elements": {},
"pack_assignments": {}
}
}
'import requests
url = "https://api.example.com/api/partner/v1/slideshows/generate"
payload = {
"prompt": "<string>",
"product_id": {},
"pack_id": {},
"image_sourcing": "<string>",
"slide_count": 123,
"slideshow_type": "<string>",
"aspect_ratio": "<string>",
"language": "<string>",
"advanced_settings": {
"font_size": {},
"text_preset": "<string>",
"text_width": "<string>"
},
"skip_ai": True,
"slide_config": {
"total_slides": 123,
"slide_types": [{}],
"custom_images": {},
"pinned_images": {},
"slide_texts": {},
"slide_text_elements": {},
"pack_assignments": {}
}
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
prompt: '<string>',
product_id: {},
pack_id: {},
image_sourcing: '<string>',
slide_count: 123,
slideshow_type: '<string>',
aspect_ratio: '<string>',
language: '<string>',
advanced_settings: {font_size: {}, text_preset: '<string>', text_width: '<string>'},
skip_ai: true,
slide_config: {
total_slides: 123,
slide_types: [{}],
custom_images: {},
pinned_images: {},
slide_texts: {},
slide_text_elements: {},
pack_assignments: {}
}
})
};
fetch('https://api.example.com/api/partner/v1/slideshows/generate', 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://api.example.com/api/partner/v1/slideshows/generate",
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([
'prompt' => '<string>',
'product_id' => [
],
'pack_id' => [
],
'image_sourcing' => '<string>',
'slide_count' => 123,
'slideshow_type' => '<string>',
'aspect_ratio' => '<string>',
'language' => '<string>',
'advanced_settings' => [
'font_size' => [
],
'text_preset' => '<string>',
'text_width' => '<string>'
],
'skip_ai' => true,
'slide_config' => [
'total_slides' => 123,
'slide_types' => [
[
]
],
'custom_images' => [
],
'pinned_images' => [
],
'slide_texts' => [
],
'slide_text_elements' => [
],
'pack_assignments' => [
]
]
]),
CURLOPT_HTTPHEADER => [
"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://api.example.com/api/partner/v1/slideshows/generate"
payload := strings.NewReader("{\n \"prompt\": \"<string>\",\n \"product_id\": {},\n \"pack_id\": {},\n \"image_sourcing\": \"<string>\",\n \"slide_count\": 123,\n \"slideshow_type\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"language\": \"<string>\",\n \"advanced_settings\": {\n \"font_size\": {},\n \"text_preset\": \"<string>\",\n \"text_width\": \"<string>\"\n },\n \"skip_ai\": true,\n \"slide_config\": {\n \"total_slides\": 123,\n \"slide_types\": [\n {}\n ],\n \"custom_images\": {},\n \"pinned_images\": {},\n \"slide_texts\": {},\n \"slide_text_elements\": {},\n \"pack_assignments\": {}\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
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://api.example.com/api/partner/v1/slideshows/generate")
.header("Content-Type", "application/json")
.body("{\n \"prompt\": \"<string>\",\n \"product_id\": {},\n \"pack_id\": {},\n \"image_sourcing\": \"<string>\",\n \"slide_count\": 123,\n \"slideshow_type\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"language\": \"<string>\",\n \"advanced_settings\": {\n \"font_size\": {},\n \"text_preset\": \"<string>\",\n \"text_width\": \"<string>\"\n },\n \"skip_ai\": true,\n \"slide_config\": {\n \"total_slides\": 123,\n \"slide_types\": [\n {}\n ],\n \"custom_images\": {},\n \"pinned_images\": {},\n \"slide_texts\": {},\n \"slide_text_elements\": {},\n \"pack_assignments\": {}\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/partner/v1/slideshows/generate")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"prompt\": \"<string>\",\n \"product_id\": {},\n \"pack_id\": {},\n \"image_sourcing\": \"<string>\",\n \"slide_count\": 123,\n \"slideshow_type\": \"<string>\",\n \"aspect_ratio\": \"<string>\",\n \"language\": \"<string>\",\n \"advanced_settings\": {\n \"font_size\": {},\n \"text_preset\": \"<string>\",\n \"text_width\": \"<string>\"\n },\n \"skip_ai\": true,\n \"slide_config\": {\n \"total_slides\": 123,\n \"slide_types\": [\n {}\n ],\n \"custom_images\": {},\n \"pinned_images\": {},\n \"slide_texts\": {},\n \"slide_text_elements\": {},\n \"pack_assignments\": {}\n }\n}"
response = http.request(request)
puts response.read_bodyCreate a new slideshow in the authenticated key scope. This is the core content creation endpoint - your OpenClaw agent or automation script generates slideshows here, then publishes them to media-capable accounts via Create Post.
Pinterest auto mode (
Manual mode (
generate supports:
- AI generation from a prompt/product context
- manual initial slide setup (
skip_ai=true) - mixed setup with explicit
slide_config
Idempotency
Send a uniqueIdempotency-Key header for each slideshow you intend to create. Retrying the same
key with the same body replays the original result. When the header is omitted, Genviral derives a
stable key from the credential and request body for backward compatibility, so an identical
headerless request is treated as a retry rather than a new generation.
Body Parameters
string
Prompt used for AI text generation. Required unless
skip_ai=true or product_id is provided.string (UUID)
Optional product reference. Must exist in the authenticated key scope.
string (UUID)
Optional global image pack ID. Required whenever any generated slide uses
image_pack and no
per-slide pack_assignments are provided, unless image_sourcing allows Pinterest sourcing.string
Optional image sourcing mode. Default:
pack (backward compatible).pack— shuffle backgrounds frompack_idor per-slidepack_assignmentsonlypinterest_auto— run the whole-deck Pinterest agent after text generation;pack_idoptionalpinterest_then_pack— Pinterest first, then fill missing slides from scoped/public packs whenpack_idis omitted
number
Optional target slide count (
1-10). Default: 5.string
Optional:
educational or personal. Default: educational.string
Optional:
9:16, 1:1, or 4:5. Default: 4:5.string
Optional language hint (2-32 chars).
object
Optional text styling defaults.
Show advanced_settings object
Show advanced_settings object
string | number
default, small, or a numeric size (8-200). Preset mapping for generated slides:
default = title/single 48px, body 40px; small = title/single 40px, body 33px
(rounded from 0.83x). If users ask for “a bit bigger than small”, use a numeric midpoint
such as 44.string
Text style preset (for example
tiktok).string
default or narrow.boolean
Optional. When
true, generation skips AI text creation and uses your slide_config input.object
Optional explicit per-slide setup.
Show slide_config object
Show slide_config object
number
required
Integer
1-10.array
required
Exact-length array matching
total_slides. Values: image_pack or
custom_image.object
Map of slide index -> custom image payload. Required for every
custom_image slide.object
Optional map of slide index -> pinned image URL.
object
Optional map of slide index -> text string.
object
Optional map of slide index -> text element array
(
content, x, y, optional id, font_size, width).object
Optional map of slide index -> pack UUID. Valid only for
image_pack
slides.All
slide_config map keys must be 0-based numeric indices in range. image_pack slides must
resolve a pack via pack_id, pack_assignments[index], or an image_sourcing mode that allows
Pinterest sourcing (pinterest_auto, pinterest_then_pack).Examples
AI mode (prompt + global pack)
cURL
curl --request POST \
--url https://www.genviral.io/api/partner/v1/slideshows/generate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: slideshow-discipline-quotes-v1' \
--data '{
"prompt": "5 discipline quotes",
"pack_id": "11111111-1111-1111-1111-111111111111",
"slide_count": 1,
"slideshow_type": "educational",
"aspect_ratio": "4:5",
"language": "en",
"advanced_settings": {
"font_size": 44,
"text_preset": "tiktok",
"text_width": "default"
}
}'
Pinterest auto mode (image_sourcing=pinterest_auto)
cURL
curl --request POST \
--url https://www.genviral.io/api/partner/v1/slideshows/generate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"prompt": "5 morning routine tips for busy parents",
"product_id": "22222222-2222-2222-2222-222222222222",
"image_sourcing": "pinterest_auto",
"slide_count": 5,
"slideshow_type": "educational",
"aspect_ratio": "4:5"
}'
Manual mode (skip_ai=true)
cURL
curl --request POST \
--url https://www.genviral.io/api/partner/v1/slideshows/generate \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '{
"skip_ai": true,
"slide_config": {
"total_slides": 2,
"slide_types": ["custom_image", "image_pack"],
"custom_images": {
"0": {
"image_url": "https://cdn.example.com/custom-0.jpg",
"image_id": "hero_0"
}
},
"slide_text_elements": {
"0": [
{
"content": "Hook text",
"x": 50,
"y": 25
}
]
},
"pack_assignments": {
"1": "11111111-1111-1111-1111-111111111111"
}
}
}'
Response
Returns201 with the full slideshow object (same structure as
Get Slideshow).
Response
{
"ok": true,
"code": 201,
"message": "Slideshow generated",
"data": {
"id": "2ab58bb0-0c39-45c0-a4d5-b6852f9d7fc0",
"title": "5 discipline quotes",
"status": "draft",
"slideshow_type": "educational",
"product_id": null,
"original_prompt": "5 discipline quotes",
"preview_image_url": null,
"created_at": "2026-02-14T09:20:00.000Z",
"updated_at": "2026-02-14T09:20:00.000Z",
"last_rendered_at": null,
"slide_count": 1,
"settings": {
"image_pack_id": "11111111-1111-1111-1111-111111111111",
"aspect_ratio": "4:5",
"slideshow_type": "educational",
"advanced_settings": {
"font_size": 44,
"text_preset": "tiktok",
"text_width": "default"
},
"pack_assignments": null
},
"slides": [
{
"index": 0,
"image_url": "https://cdn.example.com/slides/discipline-1.jpg",
"rendered_image_url": null,
"text_elements": [
{
"id": "9fd0b2bd-a95a-4488-8b7a-bf1d18d2bcdf",
"content": "Discipline beats motivation",
"x": 50,
"y": 25,
"font_size": 48,
"width": 70,
"height": null,
"editable": true,
"style_preset": "tiktok",
"font_family": null,
"background_color": null,
"text_color": null,
"border_radius": null
}
],
"grid_images": null,
"grid_type": null,
"background_filters": null,
"image_overlays": null
}
]
}
}
Error Responses
400 invalid_json- body is not valid JSON422 invalid_payload- schema/validation failed404 pack_not_found- referenced pack is missing or outside key scope422 pack_empty- selected pack has no images422 pack_required- one or moreimage_packslides are missing pack resolution404 product_not_found-product_iddoes not exist403 forbidden_product_access-product_idexists but is outside key scope401- authentication failed (missing/invalid/revoked token)402 subscription_required- active Creator/Professional/Business plan required402 insufficient_credits- buy a credit pack athttps://www.genviral.io/billing?tab=credits, then retry403 tier_not_allowed- Scheduler tier cannot use Partner API500 generate_failed- unexpected generation failure
