Render Project
curl --request POST \
--url https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render \
--header 'Authorization: <authorization>'import requests
url = "https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render"
headers = {"Authorization": "<authorization>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: '<authorization>'}};
fetch('https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/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/projects/{projectid}/render",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "<authorization>")
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/projects/{projectid}/render")
.header("Authorization", "<authorization>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"jobId": "265a7c1a-4985-4058-9208-68114f131a2b"
}
}
{
"message": "Unauthorized"
}
{
"success": false,
"message": "Project not found"
}
{
"success": false,
"message": "Project is already being rendered"
}
Videos
Render Project
Initiate the rendering process for a project to generate the final video output based on the current project configuration and content.
POST
/
pictoryapis
/
v2
/
projects
/
{projectid}
/
render
Render Project
curl --request POST \
--url https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render \
--header 'Authorization: <authorization>'import requests
url = "https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render"
headers = {"Authorization": "<authorization>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: '<authorization>'}};
fetch('https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/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/projects/{projectid}/render",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "<authorization>")
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/projects/{projectid}/render")
.header("Authorization", "<authorization>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"jobId": "265a7c1a-4985-4058-9208-68114f131a2b"
}
}
{
"message": "Unauthorized"
}
{
"success": false,
"message": "Project not found"
}
{
"success": false,
"message": "Project is already being rendered"
}
Overview
Initiate the rendering process for an existing Pictory project to generate the final video output. This endpoint creates a render job that processes your project’s scenes, audio, subtitles, and visual effects into a complete video file. The rendering happens asynchronously, and you can track progress using the job ID returned in the response.This endpoint renders existing Pictory projects. Projects can be created via the Create Storyboard Preview API with
saveProject: true, or directly in the Pictory App.Automation Workflow: Create or edit projects in the Pictory App, then use this API to trigger rendering programmatically as part of your automation pipeline.
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 | This API | Render existing project created in App or via API |
| Direct Render | Render Storyboard Video | Skip preview, render directly from input |
When to Use This Endpoint
App-Created Projects
Render projects created and edited in the Pictory web application
Saved API Projects
Render projects saved via Storyboard API with saveProject: true
Automation Pipelines
Integrate project rendering into automated workflows
Re-rendering
Re-render projects after manual edits in the App
API Endpoint
POST https://api.pictory.ai/pictoryapis/v2/projects/{projectid}/render
Request Parameters
Path Parameters
string
required
The unique identifier of the project to render. Get from Get Projects API.
Headers
string
required
API key for authentication (starts with
pictai_)Authorization: YOUR_API_KEY
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"
}
}
{
"message": "Unauthorized"
}
{
"success": false,
"message": "Project not found"
}
{
"success": false,
"message": "Project is already being rendered"
}
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 key that starts with pictai_curl --request POST \
--url 'https://api.pictory.ai/pictoryapis/v2/projects/YOUR_PROJECT_ID/render' \
--header 'Authorization: YOUR_API_KEY' \
--header 'accept: application/json' | python -m json.tool
import requests
project_id = "20251222191648030d7df02f5b4054d4ca8831f1369459e25"
url = f"https://api.pictory.ai/pictoryapis/v2/projects/{project_id}/render"
headers = {
"Authorization": "YOUR_API_KEY",
"accept": "application/json"
}
response = requests.post(url, headers=headers)
result = response.json()
if result.get('success'):
job_id = result['data']['jobId']
print(f"Render job started: {job_id}")
else:
print(f"Failed to start render: {result.get('message')}")
const projectId = '20251222191648030d7df02f5b4054d4ca8831f1369459e25';
const response = await fetch(
`https://api.pictory.ai/pictoryapis/v2/projects/${projectId}/render`,
{
method: 'POST',
headers: {
'Authorization': 'YOUR_API_KEY',
'accept': 'application/json'
}
}
);
const result = await response.json();
if (result.success) {
const jobId = result.data.jobId;
console.log(`Render job started: ${jobId}`);
} else {
console.log(`Failed to start render: ${result.message}`);
}
<?php
$projectId = '20251222191648030d7df02f5b4054d4ca8831f1369459e25';
$url = "https://api.pictory.ai/pictoryapis/v2/projects/{$projectId}/render";
$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',
'accept: application/json'
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 200) {
$result = json_decode($response, true);
if ($result['success']) {
$jobId = $result['data']['jobId'];
echo "Render job started: {$jobId}" . PHP_EOL;
} else {
echo "Failed to start render: {$result['message']}" . PHP_EOL;
}
} else {
echo "Request failed with status {$httpCode}" . PHP_EOL;
}
?>
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
)
type RenderResponse struct {
Success bool `json:"success"`
Data struct {
JobID string `json:"jobId"`
} `json:"data"`
Message string `json:"message"`
}
func main() {
projectID := "20251222191648030d7df02f5b4054d4ca8831f1369459e25"
url := fmt.Sprintf("https://api.pictory.ai/pictoryapis/v2/projects/%s/render", projectID)
req, err := http.NewRequest("POST", url, nil)
if err != nil {
panic(err)
}
req.Header.Set("Authorization", "YOUR_API_KEY")
req.Header.Set("accept", "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 RenderResponse
json.Unmarshal(body, &result)
if result.Success {
fmt.Printf("Render job started: %s\n", result.Data.JobID)
} else {
fmt.Printf("Failed to start render: %s\n", result.Message)
}
}
Usage Notes
Asynchronous Processing: Rendering happens asynchronously. The API returns immediately with a job ID. Use the Get Video Render Job by ID API to poll and track rendering progress.
Rendering Time: Rendering time varies based on project complexity, video length, number of scenes, and applied effects. Simple projects may render in minutes, while complex projects can take longer.
Job Status Polling: Poll the Get Video Render Job by ID API periodically (recommended: every 10–30 seconds) to determine when the video is ready. The completed job response includes the
videoURL.Rendering Behavior
What Happens During Rendering
- Job Creation: A render job is created and queued in the rendering system
- Processing: The system processes all project elements:
- Compiles all scene visuals (images/videos)
- Generates and synchronizes voice-over audio
- Applies text overlays and subtitle formatting
- Processes transitions and effects
- Combines all elements into the final video
- Encoding: The final video is encoded in the specified format and quality
- Completion: The job status changes to complete, and video URLs become available
Code Examples: 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 projectId = 'your-project-id';
const response = await fetch(
`https://api.pictory.ai/pictoryapis/v2/projects/${projectId}/render`,
{
method: 'POST',
headers: { 'Authorization': 'YOUR_API_KEY' }
}
);
const result = await response.json();
const videoResult = await waitForVideo(result.data.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
project_id = 'your-project-id'
render_response = requests.post(
f'https://api.pictory.ai/pictoryapis/v2/projects/{project_id}/render',
headers={'Authorization': 'YOUR_API_KEY'}
)
result = render_response.json()
video_result = wait_for_video(result['data']['jobId'], 'YOUR_API_KEY')
Best Practices
Polling Strategy
- Start Interval: Begin with 10-second intervals for the first minute
- Increase Gradually: Increase to 15-30 seconds for longer renders
- Maximum Attempts: Set a reasonable timeout (e.g., 20-30 minutes)
- Exponential Backoff: Use increasing intervals to reduce API calls
Error Handling
- Retry Logic: Implement automatic retry for transient failures
- Timeout Handling: Set appropriate timeouts based on project complexity
- Status Validation: Always check the response status before proceeding
- Fallback Strategy: Have a plan for handling permanent failures
Related APIs
Get Render Job Status
Monitor rendering progress
Get Projects
List projects to get project IDs
Get Project By Id
Get project details and video URL
Create Storyboard Preview
Create new video projects via API
Was this page helpful?
