Render Storyboard Video
curl --request POST \
--url https://api.pictory.ai/pictoryapis/v2/video/storyboard/render \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"videoName": "<string>",
"videoWidth": 123,
"videoHeight": 123,
"aspectRatio": "<string>",
"language": "<string>",
"saveProject": true,
"webhook": "<string>",
"webhookInput": {},
"templateId": "<string>",
"variables": {},
"brandId": "<string>",
"brandName": "<string>",
"smartLayoutName": "<string>",
"smartLayoutId": "<string>",
"storyboardVersion": "<string>",
"subtitleStyleId": "<string>",
"subtitleStyleName": "<string>",
"subtitleStyle": {},
"awsConnectionId": "<string>",
"vimeoConnectionId": "<string>",
"destinations": [
{}
],
"voiceOver": {},
"backgroundMusic": {},
"logo": {},
"scenes": [
{}
]
}
'import requests
url = "https://api.pictory.ai/pictoryapis/v2/video/storyboard/render"
payload = {
"videoName": "<string>",
"videoWidth": 123,
"videoHeight": 123,
"aspectRatio": "<string>",
"language": "<string>",
"saveProject": True,
"webhook": "<string>",
"webhookInput": {},
"templateId": "<string>",
"variables": {},
"brandId": "<string>",
"brandName": "<string>",
"smartLayoutName": "<string>",
"smartLayoutId": "<string>",
"storyboardVersion": "<string>",
"subtitleStyleId": "<string>",
"subtitleStyleName": "<string>",
"subtitleStyle": {},
"awsConnectionId": "<string>",
"vimeoConnectionId": "<string>",
"destinations": [{}],
"voiceOver": {},
"backgroundMusic": {},
"logo": {},
"scenes": [{}]
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
videoName: '<string>',
videoWidth: 123,
videoHeight: 123,
aspectRatio: '<string>',
language: '<string>',
saveProject: true,
webhook: '<string>',
webhookInput: {},
templateId: '<string>',
variables: {},
brandId: '<string>',
brandName: '<string>',
smartLayoutName: '<string>',
smartLayoutId: '<string>',
storyboardVersion: '<string>',
subtitleStyleId: '<string>',
subtitleStyleName: '<string>',
subtitleStyle: {},
awsConnectionId: '<string>',
vimeoConnectionId: '<string>',
destinations: [{}],
voiceOver: {},
backgroundMusic: {},
logo: {},
scenes: [{}]
})
};
fetch('https://api.pictory.ai/pictoryapis/v2/video/storyboard/render', 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.pictory.ai/pictoryapis/v2/video/storyboard/render",
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([
'videoName' => '<string>',
'videoWidth' => 123,
'videoHeight' => 123,
'aspectRatio' => '<string>',
'language' => '<string>',
'saveProject' => true,
'webhook' => '<string>',
'webhookInput' => [
],
'templateId' => '<string>',
'variables' => [
],
'brandId' => '<string>',
'brandName' => '<string>',
'smartLayoutName' => '<string>',
'smartLayoutId' => '<string>',
'storyboardVersion' => '<string>',
'subtitleStyleId' => '<string>',
'subtitleStyleName' => '<string>',
'subtitleStyle' => [
],
'awsConnectionId' => '<string>',
'vimeoConnectionId' => '<string>',
'destinations' => [
[
]
],
'voiceOver' => [
],
'backgroundMusic' => [
],
'logo' => [
],
'scenes' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.pictory.ai/pictoryapis/v2/video/storyboard/render"
payload := strings.NewReader("{\n \"videoName\": \"<string>\",\n \"videoWidth\": 123,\n \"videoHeight\": 123,\n \"aspectRatio\": \"<string>\",\n \"language\": \"<string>\",\n \"saveProject\": true,\n \"webhook\": \"<string>\",\n \"webhookInput\": {},\n \"templateId\": \"<string>\",\n \"variables\": {},\n \"brandId\": \"<string>\",\n \"brandName\": \"<string>\",\n \"smartLayoutName\": \"<string>\",\n \"smartLayoutId\": \"<string>\",\n \"storyboardVersion\": \"<string>\",\n \"subtitleStyleId\": \"<string>\",\n \"subtitleStyleName\": \"<string>\",\n \"subtitleStyle\": {},\n \"awsConnectionId\": \"<string>\",\n \"vimeoConnectionId\": \"<string>\",\n \"destinations\": [\n {}\n ],\n \"voiceOver\": {},\n \"backgroundMusic\": {},\n \"logo\": {},\n \"scenes\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.pictory.ai/pictoryapis/v2/video/storyboard/render")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"videoName\": \"<string>\",\n \"videoWidth\": 123,\n \"videoHeight\": 123,\n \"aspectRatio\": \"<string>\",\n \"language\": \"<string>\",\n \"saveProject\": true,\n \"webhook\": \"<string>\",\n \"webhookInput\": {},\n \"templateId\": \"<string>\",\n \"variables\": {},\n \"brandId\": \"<string>\",\n \"brandName\": \"<string>\",\n \"smartLayoutName\": \"<string>\",\n \"smartLayoutId\": \"<string>\",\n \"storyboardVersion\": \"<string>\",\n \"subtitleStyleId\": \"<string>\",\n \"subtitleStyleName\": \"<string>\",\n \"subtitleStyle\": {},\n \"awsConnectionId\": \"<string>\",\n \"vimeoConnectionId\": \"<string>\",\n \"destinations\": [\n {}\n ],\n \"voiceOver\": {},\n \"backgroundMusic\": {},\n \"logo\": {},\n \"scenes\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pictory.ai/pictoryapis/v2/video/storyboard/render")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"videoName\": \"<string>\",\n \"videoWidth\": 123,\n \"videoHeight\": 123,\n \"aspectRatio\": \"<string>\",\n \"language\": \"<string>\",\n \"saveProject\": true,\n \"webhook\": \"<string>\",\n \"webhookInput\": {},\n \"templateId\": \"<string>\",\n \"variables\": {},\n \"brandId\": \"<string>\",\n \"brandName\": \"<string>\",\n \"smartLayoutName\": \"<string>\",\n \"smartLayoutId\": \"<string>\",\n \"storyboardVersion\": \"<string>\",\n \"subtitleStyleId\": \"<string>\",\n \"subtitleStyleName\": \"<string>\",\n \"subtitleStyle\": {},\n \"awsConnectionId\": \"<string>\",\n \"vimeoConnectionId\": \"<string>\",\n \"destinations\": [\n {}\n ],\n \"voiceOver\": {},\n \"backgroundMusic\": {},\n \"logo\": {},\n \"scenes\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"jobId": "265a7c1a-4985-4058-9208-68114f131a2b"
}
}
{
"code": "INVALID_REQUEST_BODY",
"message": "Request body validation failed.",
"fields": [
{
"name": "scenes",
"errors": "scenes is required"
}
]
}
{
"message": "Unauthorized"
}
Videos
Render Storyboard Video
Render a final video from a storyboard with all scenes, visuals, voice-over, and effects
POST
/
pictoryapis
/
v2
/
video
/
storyboard
/
render
Render Storyboard Video
curl --request POST \
--url https://api.pictory.ai/pictoryapis/v2/video/storyboard/render \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"videoName": "<string>",
"videoWidth": 123,
"videoHeight": 123,
"aspectRatio": "<string>",
"language": "<string>",
"saveProject": true,
"webhook": "<string>",
"webhookInput": {},
"templateId": "<string>",
"variables": {},
"brandId": "<string>",
"brandName": "<string>",
"smartLayoutName": "<string>",
"smartLayoutId": "<string>",
"storyboardVersion": "<string>",
"subtitleStyleId": "<string>",
"subtitleStyleName": "<string>",
"subtitleStyle": {},
"awsConnectionId": "<string>",
"vimeoConnectionId": "<string>",
"destinations": [
{}
],
"voiceOver": {},
"backgroundMusic": {},
"logo": {},
"scenes": [
{}
]
}
'import requests
url = "https://api.pictory.ai/pictoryapis/v2/video/storyboard/render"
payload = {
"videoName": "<string>",
"videoWidth": 123,
"videoHeight": 123,
"aspectRatio": "<string>",
"language": "<string>",
"saveProject": True,
"webhook": "<string>",
"webhookInput": {},
"templateId": "<string>",
"variables": {},
"brandId": "<string>",
"brandName": "<string>",
"smartLayoutName": "<string>",
"smartLayoutId": "<string>",
"storyboardVersion": "<string>",
"subtitleStyleId": "<string>",
"subtitleStyleName": "<string>",
"subtitleStyle": {},
"awsConnectionId": "<string>",
"vimeoConnectionId": "<string>",
"destinations": [{}],
"voiceOver": {},
"backgroundMusic": {},
"logo": {},
"scenes": [{}]
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
videoName: '<string>',
videoWidth: 123,
videoHeight: 123,
aspectRatio: '<string>',
language: '<string>',
saveProject: true,
webhook: '<string>',
webhookInput: {},
templateId: '<string>',
variables: {},
brandId: '<string>',
brandName: '<string>',
smartLayoutName: '<string>',
smartLayoutId: '<string>',
storyboardVersion: '<string>',
subtitleStyleId: '<string>',
subtitleStyleName: '<string>',
subtitleStyle: {},
awsConnectionId: '<string>',
vimeoConnectionId: '<string>',
destinations: [{}],
voiceOver: {},
backgroundMusic: {},
logo: {},
scenes: [{}]
})
};
fetch('https://api.pictory.ai/pictoryapis/v2/video/storyboard/render', 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.pictory.ai/pictoryapis/v2/video/storyboard/render",
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([
'videoName' => '<string>',
'videoWidth' => 123,
'videoHeight' => 123,
'aspectRatio' => '<string>',
'language' => '<string>',
'saveProject' => true,
'webhook' => '<string>',
'webhookInput' => [
],
'templateId' => '<string>',
'variables' => [
],
'brandId' => '<string>',
'brandName' => '<string>',
'smartLayoutName' => '<string>',
'smartLayoutId' => '<string>',
'storyboardVersion' => '<string>',
'subtitleStyleId' => '<string>',
'subtitleStyleName' => '<string>',
'subtitleStyle' => [
],
'awsConnectionId' => '<string>',
'vimeoConnectionId' => '<string>',
'destinations' => [
[
]
],
'voiceOver' => [
],
'backgroundMusic' => [
],
'logo' => [
],
'scenes' => [
[
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.pictory.ai/pictoryapis/v2/video/storyboard/render"
payload := strings.NewReader("{\n \"videoName\": \"<string>\",\n \"videoWidth\": 123,\n \"videoHeight\": 123,\n \"aspectRatio\": \"<string>\",\n \"language\": \"<string>\",\n \"saveProject\": true,\n \"webhook\": \"<string>\",\n \"webhookInput\": {},\n \"templateId\": \"<string>\",\n \"variables\": {},\n \"brandId\": \"<string>\",\n \"brandName\": \"<string>\",\n \"smartLayoutName\": \"<string>\",\n \"smartLayoutId\": \"<string>\",\n \"storyboardVersion\": \"<string>\",\n \"subtitleStyleId\": \"<string>\",\n \"subtitleStyleName\": \"<string>\",\n \"subtitleStyle\": {},\n \"awsConnectionId\": \"<string>\",\n \"vimeoConnectionId\": \"<string>\",\n \"destinations\": [\n {}\n ],\n \"voiceOver\": {},\n \"backgroundMusic\": {},\n \"logo\": {},\n \"scenes\": [\n {}\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.pictory.ai/pictoryapis/v2/video/storyboard/render")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"videoName\": \"<string>\",\n \"videoWidth\": 123,\n \"videoHeight\": 123,\n \"aspectRatio\": \"<string>\",\n \"language\": \"<string>\",\n \"saveProject\": true,\n \"webhook\": \"<string>\",\n \"webhookInput\": {},\n \"templateId\": \"<string>\",\n \"variables\": {},\n \"brandId\": \"<string>\",\n \"brandName\": \"<string>\",\n \"smartLayoutName\": \"<string>\",\n \"smartLayoutId\": \"<string>\",\n \"storyboardVersion\": \"<string>\",\n \"subtitleStyleId\": \"<string>\",\n \"subtitleStyleName\": \"<string>\",\n \"subtitleStyle\": {},\n \"awsConnectionId\": \"<string>\",\n \"vimeoConnectionId\": \"<string>\",\n \"destinations\": [\n {}\n ],\n \"voiceOver\": {},\n \"backgroundMusic\": {},\n \"logo\": {},\n \"scenes\": [\n {}\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pictory.ai/pictoryapis/v2/video/storyboard/render")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"videoName\": \"<string>\",\n \"videoWidth\": 123,\n \"videoHeight\": 123,\n \"aspectRatio\": \"<string>\",\n \"language\": \"<string>\",\n \"saveProject\": true,\n \"webhook\": \"<string>\",\n \"webhookInput\": {},\n \"templateId\": \"<string>\",\n \"variables\": {},\n \"brandId\": \"<string>\",\n \"brandName\": \"<string>\",\n \"smartLayoutName\": \"<string>\",\n \"smartLayoutId\": \"<string>\",\n \"storyboardVersion\": \"<string>\",\n \"subtitleStyleId\": \"<string>\",\n \"subtitleStyleName\": \"<string>\",\n \"subtitleStyle\": {},\n \"awsConnectionId\": \"<string>\",\n \"vimeoConnectionId\": \"<string>\",\n \"destinations\": [\n {}\n ],\n \"voiceOver\": {},\n \"backgroundMusic\": {},\n \"logo\": {},\n \"scenes\": [\n {}\n ]\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"jobId": "265a7c1a-4985-4058-9208-68114f131a2b"
}
}
{
"code": "INVALID_REQUEST_BODY",
"message": "Request body validation failed.",
"fields": [
{
"name": "scenes",
"errors": "scenes is required"
}
]
}
{
"message": "Unauthorized"
}
Overview
The Render Storyboard Video API generates the final rendered video file from your storyboard configuration. This endpoint processes all scenes, applies voice-over narration, background music, visual effects, and produces a complete video ready for distribution.This endpoint renders the final video directly. For a preview-first workflow, use the Create Storyboard Preview API to review scenes before rendering.
Direct Render: Use this endpoint when you are confident in your content and want to skip the preview step, or when re-rendering a previously approved storyboard.
Render Workflow Options
| Workflow | API | When to Use |
|---|---|---|
| Create Preview | Create Storyboard Preview | Generate preview to review scenes before rendering |
| Render from Preview | Render from Preview | Render preview as-is without modifications |
| Render with Modifications | Render Video | Modify preview elements before rendering |
| Render Saved Project | Render Project | Render existing project created in App or via API |
| Direct Render | This API | Skip preview, render directly from input |
Preview vs. Final Render
| Aspect | Storyboard Preview | Final Render |
|---|---|---|
| Purpose | Review and validate content | Produce final video file |
| Output | Scene thumbnails, metadata, project structure | Full HD video file |
| Speed | Fast | Slower |
| Cost | Lower resource usage | Full rendering resources |
| Editable | Yes, make changes before render | Video is final |
| Use Case | Content approval, iteration | Final delivery |
Use Cases
Direct Video Creation
Generate final videos directly from text, articles, or presentations
Batch Rendering
Render multiple videos programmatically at scale
Automated Pipelines
Integrate into automated content creation workflows
Re-rendering
Re-render videos after making adjustments to projects
Template-based Videos
Generate videos from templates with variable content
Multi-platform Content
Create videos for different platforms with aspect ratios
API Endpoint
POST https://api.pictory.ai/pictoryapis/v2/video/storyboard/render
Request Headers
string
required
API key for authentication
Authorization: YOUR_API_KEY
string
required
Must be
application/jsonRequest Body Parameters
The request body accepts the same parameters as the Create Storyboard Preview API. All parameters for video configuration, scenes, voice-over, background music, branding, and destinations are supported.string
required
Name for your video project (alphanumeric, spaces, underscores, and hyphens only, max 150 characters)
integer
Width of the generated video in pixels. Must be provided together with
videoHeight.integer
Height of the generated video in pixels. Must be provided together with
videoWidth.string
Video aspect ratio. Options:
1:1, 16:9, 9:16, 4:5string
Language of the text content.Allowed values:
zh, nl, en, fr, de, hi, it, ja, ko, mr, pt, ru, es, tazh Chinese, nl Dutch, en English, fr French, de German, hi Hindi, it Italian, ja Japanese, ko Korean, mr Marathi, pt Portuguese, ru Russian, es Spanish, ta Tamilboolean
Whether to save the project in your Pictory account for later editing. Default:
falsestring
URL where the completed video output will be sent via POST request when finished (max 500 characters)
object
Custom data object that will be included in the webhook POST payload when the job completes. Use this to pass through any metadata (e.g., internal IDs, tracking info) that you need in your webhook handler.
{
"webhookInput": {
"internalId": "abc-123",
"source": "campaign-builder"
}
}
string
ID of a template to use. Get from Get Templates API.
object
Key-value object for template variables. Only applicable when
templateId is provided.{
"variables": {
"headline": "Welcome to Our Product",
"subheadline": "Discover Amazing Features",
"ctaText": "Learn More"
}
}
string
ID of the brand to apply. Get from Get Video Brands API. Cannot be used with
brandName.string
Name of the brand to apply. Cannot be used with
brandId.string
Name of the smart layout to apply. Get available layouts from Get Smart Layouts API. Cannot be used with
smartLayoutId.string
ID of the smart layout to apply. Get from Get Smart Layouts API. Cannot be used with
smartLayoutName.string
Experimental: This field is currently experimental. In the future, all storyboards will automatically use the latest version, and this field will be ignored. There is no need to remove it from your requests when that happens.
v3 to create a latest Pictory storyboard. Omit this field to use the classic storyboard.Options:v3: Uses the latest Pictory storyboard- Omit or any other value: Uses the classic/legacy storyboard
string
ID of a saved text style for subtitles. Get from Get Text Styles API. Cannot be used with
subtitleStyleName.string
Name of a saved text style for subtitles. Cannot be used with
subtitleStyleId.object
Inline subtitle style configuration. See Create Storyboard Preview - subtitleStyle Object.
{
"subtitleStyle": {
"fontFamily": "Montserrat",
"fontSize": 48,
"color": "rgba(255,255,255,1)",
"backgroundColor": "rgba(0,0,0,0.5)",
"position": "bottom-center",
"alignment": "center"
}
}
string
AWS connection ID for accessing private S3 assets. Get from Get AWS Connections API.
string
Vimeo connection ID for uploading videos directly to Vimeo. Get from Get Vimeo Connections API.
array
Array of destination configurations for uploading the generated video (max 5). See Create Storyboard Preview - destinations Array.
{
"destinations": [
{
"type": "vimeo",
"folder_uri": "/users/12345/projects/67890",
"content_rating": ["safe"],
"privacy": {
"view": "unlisted",
"embed": "public",
"download": false
}
}
]
}
object
Voice-over configuration for AI narration. See Create Storyboard Preview - voiceOver Object.
{
"voiceOver": {
"enabled": true,
"aiVoices": [
{
"speaker": "Brian",
"speed": 100,
"amplificationLevel": 0
}
]
}
}
object
Background music configuration for the video. See Create Storyboard Preview - backgroundMusic Object.
{
"backgroundMusic": {
"enabled": true,
"autoMusic": true,
"volume": 0.5
}
}
object
Logo overlay configuration. See Create Storyboard Preview - logo Object.
{
"logo": {
"url": "https://example.com/logo.png",
"position": "top-right",
"width": "15%"
}
}
array
required
Array of scene objects containing the content to convert into video. Required unless using
templateId. See Create Storyboard Preview - scenes Array.{
"scenes": [
{
"story": "Welcome to our product showcase. Discover amazing features.",
"createSceneOnEndOfSentence": true,
"highlightKeywords": true,
"sceneTransition": "fade",
"background": {
"visualUrl": "https://example.com/background.mp4",
"type": "video",
"settings": {
"mute": true,
"loop": true
}
}
}
]
}
Response
When the render request is successfully submitted, a job is created and a job ID is returned.boolean
Indicates whether the request was successful
object
string
Unique identifier for the render job. Use this to track the job status and retrieve results via the Get Video Render Job by ID endpoint.
{
"success": true,
"data": {
"jobId": "265a7c1a-4985-4058-9208-68114f131a2b"
}
}
{
"code": "INVALID_REQUEST_BODY",
"message": "Request body validation failed.",
"fields": [
{
"name": "scenes",
"errors": "scenes is required"
}
]
}
{
"message": "Unauthorized"
}
Next Steps
Once you have thejobId, poll the Get Video Render Job by ID endpoint to check the render status and retrieve the output URLs when complete. Use a polling interval of 10–30 seconds.
Code Examples
Replace
YOUR_API_KEY with your actual API keyBasic Text to Video Render
curl --request POST \
--url https://api.pictory.ai/pictoryapis/v2/video/storyboard/render \
--header 'Authorization: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"videoName": "my_rendered_video",
"aspectRatio": "16:9",
"voiceOver": {
"enabled": true,
"aiVoices": [{"speaker": "Brian", "speed": 100}]
},
"scenes": [
{
"story": "Welcome to our company. We create innovative solutions for modern businesses.",
"createSceneOnEndOfSentence": true
}
]
}' | python -m json.tool
const response = await fetch('https://api.pictory.ai/pictoryapis/v2/video/storyboard/render', {
method: 'POST',
headers: {
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
videoName: 'my_rendered_video',
aspectRatio: '16:9',
voiceOver: {
enabled: true,
aiVoices: [{ speaker: 'Brian', speed: 100 }]
},
scenes: [{
story: 'Welcome to our company. We create innovative solutions for modern businesses.',
createSceneOnEndOfSentence: true
}]
})
});
const data = await response.json();
console.log('Job ID:', data.data.jobId);
import requests
response = requests.post(
'https://api.pictory.ai/pictoryapis/v2/video/storyboard/render',
headers={
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'videoName': 'my_rendered_video',
'aspectRatio': '16:9',
'voiceOver': {
'enabled': True,
'aiVoices': [{'speaker': 'Brian', 'speed': 100}]
},
'scenes': [{
'story': 'Welcome to our company. We create innovative solutions for modern businesses.',
'createSceneOnEndOfSentence': True
}]
}
)
data = response.json()
print('Job ID:', data['data']['jobId'])
<?php
$url = 'https://api.pictory.ai/pictoryapis/v2/video/storyboard/render';
$payload = [
'videoName' => 'my_rendered_video',
'aspectRatio' => '16:9',
'voiceOver' => [
'enabled' => true,
'aiVoices' => [['speaker' => 'Brian', 'speed' => 100]]
],
'scenes' => [[
'story' => 'Welcome to our company. We create innovative solutions for modern businesses.',
'createSceneOnEndOfSentence' => true
]]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: YOUR_API_KEY',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo 'Job ID: ' . $data['data']['jobId'] . PHP_EOL;
?>
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.pictory.ai/pictoryapis/v2/video/storyboard/render"
payload := map[string]interface{}{
"videoName": "my_rendered_video",
"aspectRatio": "16:9",
"voiceOver": map[string]interface{}{
"enabled": true,
"aiVoices": []map[string]interface{}{
{"speaker": "Brian", "speed": 100},
},
},
"scenes": []map[string]interface{}{
{
"story": "Welcome to our company. We create innovative solutions for modern businesses.",
"createSceneOnEndOfSentence": true,
},
},
}
requestBody, _ := json.Marshal(payload)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
data := result["data"].(map[string]interface{})
fmt.Println("Job ID:", data["jobId"])
}
Render with Full Configuration
const response = await fetch('https://api.pictory.ai/pictoryapis/v2/video/storyboard/render', {
method: 'POST',
headers: {
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({
videoName: 'complete_video_render',
aspectRatio: '16:9',
saveProject: true,
webhook: 'https://your-server.com/webhook',
// Branding
brandName: 'My Brand',
// Voice-over
voiceOver: {
enabled: true,
aiVoices: [{
speaker: 'Emma',
speed: 100,
amplificationLevel: 0
}]
},
// Background music
backgroundMusic: {
enabled: true,
autoMusic: true,
volume: 0.3
},
// Logo
logo: {
url: 'https://example.com/logo.png',
position: 'top-right',
width: '15%'
},
// Subtitle styling
subtitleStyle: {
fontFamily: 'Montserrat',
fontSize: 48,
color: 'rgba(255,255,255,1)',
position: 'bottom-center'
},
// Scenes
scenes: [{
story: 'Welcome to our company. We create innovative solutions. Join us on this journey.',
createSceneOnEndOfSentence: true,
highlightKeywords: true,
sceneTransition: 'fade'
}]
})
});
const data = await response.json();
console.log('Job ID:', data.data.jobId);
import requests
response = requests.post(
'https://api.pictory.ai/pictoryapis/v2/video/storyboard/render',
headers={
'Authorization': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'videoName': 'complete_video_render',
'aspectRatio': '16:9',
'saveProject': True,
'webhook': 'https://your-server.com/webhook',
# Branding
'brandName': 'My Brand',
# Voice-over
'voiceOver': {
'enabled': True,
'aiVoices': [{
'speaker': 'Emma',
'speed': 100,
'amplificationLevel': 0
}]
},
# Background music
'backgroundMusic': {
'enabled': True,
'autoMusic': True,
'volume': 0.3
},
# Logo
'logo': {
'url': 'https://example.com/logo.png',
'position': 'top-right',
'width': '15%'
},
# Subtitle styling
'subtitleStyle': {
'fontFamily': 'Montserrat',
'fontSize': 48,
'color': 'rgba(255,255,255,1)',
'position': 'bottom-center'
},
# Scenes
'scenes': [{
'story': 'Welcome to our company. We create innovative solutions. Join us on this journey.',
'createSceneOnEndOfSentence': True,
'highlightKeywords': True,
'sceneTransition': 'fade'
}]
}
)
data = response.json()
print('Job ID:', data['data']['jobId'])
<?php
$url = 'https://api.pictory.ai/pictoryapis/v2/video/storyboard/render';
$payload = [
'videoName' => 'complete_video_render',
'aspectRatio' => '16:9',
'saveProject' => true,
'webhook' => 'https://your-server.com/webhook',
// Branding
'brandName' => 'My Brand',
// Voice-over
'voiceOver' => [
'enabled' => true,
'aiVoices' => [[
'speaker' => 'Emma',
'speed' => 100,
'amplificationLevel' => 0
]]
],
// Background music
'backgroundMusic' => [
'enabled' => true,
'autoMusic' => true,
'volume' => 0.3
],
// Logo
'logo' => [
'url' => 'https://example.com/logo.png',
'position' => 'top-right',
'width' => '15%'
],
// Subtitle styling
'subtitleStyle' => [
'fontFamily' => 'Montserrat',
'fontSize' => 48,
'color' => 'rgba(255,255,255,1)',
'position' => 'bottom-center'
],
// Scenes
'scenes' => [[
'story' => 'Welcome to our company. We create innovative solutions. Join us on this journey.',
'createSceneOnEndOfSentence' => true,
'highlightKeywords' => true,
'sceneTransition' => 'fade'
]]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: YOUR_API_KEY',
'Content-Type: application/json'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
echo 'Job ID: ' . $data['data']['jobId'] . PHP_EOL;
?>
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func main() {
url := "https://api.pictory.ai/pictoryapis/v2/video/storyboard/render"
payload := map[string]interface{}{
"videoName": "complete_video_render",
"aspectRatio": "16:9",
"saveProject": true,
"webhook": "https://your-server.com/webhook",
// Branding
"brandName": "My Brand",
// Voice-over
"voiceOver": map[string]interface{}{
"enabled": true,
"aiVoices": []map[string]interface{}{
{
"speaker": "Emma",
"speed": 100,
"amplificationLevel": 0,
},
},
},
// Background music
"backgroundMusic": map[string]interface{}{
"enabled": true,
"autoMusic": true,
"volume": 0.3,
},
// Logo
"logo": map[string]interface{}{
"url": "https://example.com/logo.png",
"position": "top-right",
"width": "15%",
},
// Subtitle styling
"subtitleStyle": map[string]interface{}{
"fontFamily": "Montserrat",
"fontSize": 48,
"color": "rgba(255,255,255,1)",
"position": "bottom-center",
},
// Scenes
"scenes": []map[string]interface{}{
{
"story": "Welcome to our company. We create innovative solutions. Join us on this journey.",
"createSceneOnEndOfSentence": true,
"highlightKeywords": true,
"sceneTransition": "fade",
},
},
}
requestBody, _ := json.Marshal(payload)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBody))
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "YOUR_API_KEY")
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result map[string]interface{}
json.Unmarshal(body, &result)
data := result["data"].(map[string]interface{})
fmt.Println("Job ID:", data["jobId"])
}
Poll for Completion
async function waitForVideo(jobId, apiKey) {
const maxAttempts = 60;
const pollInterval = 10000; // 10 seconds
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const response = await fetch(
`https://api.pictory.ai/pictoryapis/v1/jobs/${jobId}`,
{ headers: { 'Authorization': apiKey } }
);
const data = await response.json();
const status = data.data.status;
console.log(`Attempt ${attempt + 1}: Status = ${status}`);
if (status === 'completed') {
console.log('Video URL:', data.data.videoURL);
return data.data;
}
if (status === 'failed') {
throw new Error('Video rendering failed: ' + JSON.stringify(data));
}
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error('Timeout waiting for video to render');
}
// Usage
const jobId = 'your-job-id';
const result = await waitForVideo(jobId, 'YOUR_API_KEY');
import requests
import time
def wait_for_video(job_id, api_key, max_attempts=60, poll_interval=10):
for attempt in range(max_attempts):
response = requests.get(
f'https://api.pictory.ai/pictoryapis/v1/jobs/{job_id}',
headers={'Authorization': api_key}
)
data = response.json()
status = data['data']['status']
print(f'Attempt {attempt + 1}: Status = {status}')
if status == 'completed':
print('Video URL:', data['data']['videoURL'])
return data['data']
if status == 'failed':
raise Exception(f'Video rendering failed: {data}')
time.sleep(poll_interval)
raise Exception('Timeout waiting for video to render')
# Usage
job_id = 'your-job-id'
result = wait_for_video(job_id, 'YOUR_API_KEY')
<?php
function waitForVideo($jobId, $apiKey, $maxAttempts = 60, $pollInterval = 10) {
for ($attempt = 0; $attempt < $maxAttempts; $attempt++) {
$url = "https://api.pictory.ai/pictoryapis/v1/jobs/{$jobId}";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: ' . $apiKey
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
$status = $data['data']['status'];
echo "Attempt " . ($attempt + 1) . ": Status = {$status}\n";
if ($status === 'completed') {
echo "Video URL: " . $data['data']['videoURL'] . "\n";
return $data['data'];
}
if ($status === 'failed') {
throw new Exception('Video rendering failed: ' . json_encode($data));
}
sleep($pollInterval);
}
throw new Exception('Timeout waiting for video to render');
}
// Usage
$jobId = 'your-job-id';
$result = waitForVideo($jobId, 'YOUR_API_KEY');
?>
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
type JobResponse struct {
Data struct {
Status string `json:"status"`
VideoURL string `json:"videoURL"`
} `json:"data"`
}
func waitForVideo(jobID, apiKey string, maxAttempts int, pollInterval time.Duration) (*JobResponse, error) {
for attempt := 0; attempt < maxAttempts; attempt++ {
url := fmt.Sprintf("https://api.pictory.ai/pictoryapis/v1/jobs/%s", jobID)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", apiKey)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var result JobResponse
json.Unmarshal(body, &result)
status := result.Data.Status
fmt.Printf("Attempt %d: Status = %s\n", attempt+1, status)
if status == "completed" {
fmt.Printf("Video URL: %s\n", result.Data.VideoURL)
return &result, nil
}
if status == "failed" {
return nil, fmt.Errorf("video rendering failed: %s", string(body))
}
time.Sleep(pollInterval)
}
return nil, fmt.Errorf("timeout waiting for video to render")
}
func main() {
jobID := "your-job-id"
result, err := waitForVideo(jobID, "YOUR_API_KEY", 60, 10*time.Second)
if err != nil {
panic(err)
}
fmt.Printf("Video ready: %s\n", result.Data.VideoURL)
}
Related APIs
Create Storyboard Preview
Preview storyboard before rendering
Get Render Job Status
Monitor rendering progress
Get Projects
List saved video projects
Get Voiceover Tracks
List available AI voices
Was this page helpful?
⌘I
