Skip to main content
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": {},
  "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": {},
"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: {},
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' => [

],
'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 \"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 \"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 \"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_body
Create 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. generate supports:
  • AI generation from a prompt/product context
  • manual initial slide setup (skip_ai=true)
  • mixed setup with explicit slide_config

Body Parameters

prompt
string
Prompt used for AI text generation. Required unless skip_ai=true or product_id is provided.
product_id
string (UUID)
Optional product reference. Must exist in the authenticated key scope.
pack_id
string (UUID)
Optional global image pack ID. Required whenever any generated slide uses image_pack and no per-slide pack_assignments are provided.
slide_count
number
Optional target slide count (1-10). Default: 5.
slideshow_type
string
Optional: educational or personal. Default: educational.
aspect_ratio
string
Optional: 9:16, 1:1, or 4:5. Default: 4:5.
language
string
Optional language hint (2-32 chars).
advanced_settings
object
Optional text styling defaults.
skip_ai
boolean
Optional. When true, generation skips AI text creation and uses your slide_config input.
slide_config
object
Optional explicit per-slide setup.
All slide_config map keys must be 0-based numeric indices in range. image_pack slides must resolve a pack via pack_id or pack_assignments[index].

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' \
  --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"
  }
}'

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

Returns 201 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 JSON
  • 422 invalid_payload - schema/validation failed
  • 404 pack_not_found - referenced pack is missing or outside key scope
  • 422 pack_empty - selected pack has no images
  • 422 pack_required - one or more image_pack slides are missing pack resolution
  • 404 product_not_found - product_id does not exist
  • 403 forbidden_product_access - product_id exists but is outside key scope
  • 401 - authentication failed (missing/invalid/revoked token)
  • 402 subscription_required - active Creator/Professional/Business plan required
  • 403 tier_not_allowed - Scheduler tier cannot use Partner API
  • 500 generate_failed - unexpected generation failure