Get Video Generation Job
curl --request GET \
--url https://api.pictory.ai/pictoryapis/v1/jobs/{jobid} \
--header 'Authorization: <authorization>'import requests
url = "https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}"
headers = {"Authorization": "<authorization>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: '<authorization>'}};
fetch('https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}', 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/v1/jobs/{jobid}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
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/v1/jobs/{jobid}"
req, _ := http.NewRequest("GET", 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.get("https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}")
.header("Authorization", "<authorization>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = '<authorization>'
response = http.request(request)
puts response.read_body{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": true,
"data": {
"status": "in-progress"
}
}
{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": true,
"data": {
"duration": "8s",
"thumbnailImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_thumbnail.jpg",
"lastFrameImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_last_frame.png",
"previewImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_preview.jpg",
"width": 720,
"aiCreditsUsed": 12.8,
"height": 1280,
"url": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654.mp4",
"status": "completed"
}
}
{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": false,
"data": {
"status": "failed",
"error_code": "5001",
"error_message": "Video generation failed due to an internal error."
}
}
{
"id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": false,
"data": {
"error_code": "5000",
"error_message": "JOB_NOT_FOUND"
}
}
{
"message": "Unauthorized"
}
AI Studio
Get Video Generation Job
Retrieve the status and output of an AI video generation job
GET
/
pictoryapis
/
v1
/
jobs
/
{jobid}
Get Video Generation Job
curl --request GET \
--url https://api.pictory.ai/pictoryapis/v1/jobs/{jobid} \
--header 'Authorization: <authorization>'import requests
url = "https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}"
headers = {"Authorization": "<authorization>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: '<authorization>'}};
fetch('https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}', 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/v1/jobs/{jobid}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
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/v1/jobs/{jobid}"
req, _ := http.NewRequest("GET", 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.get("https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}")
.header("Authorization", "<authorization>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = '<authorization>'
response = http.request(request)
puts response.read_body{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": true,
"data": {
"status": "in-progress"
}
}
{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": true,
"data": {
"duration": "8s",
"thumbnailImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_thumbnail.jpg",
"lastFrameImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_last_frame.png",
"previewImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_preview.jpg",
"width": 720,
"aiCreditsUsed": 12.8,
"height": 1280,
"url": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654.mp4",
"status": "completed"
}
}
{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": false,
"data": {
"status": "failed",
"error_code": "5001",
"error_message": "Video generation failed due to an internal error."
}
}
{
"id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": false,
"data": {
"error_code": "5000",
"error_message": "JOB_NOT_FOUND"
}
}
{
"message": "Unauthorized"
}
Overview
This endpoint retrieves the current status and output of an AI video generation job using its unique job ID. While the generation is in progress, it returns the job status. Once the video generation completes, it returns the output including the video URL, thumbnail images, dimensions, duration, and AI credits consumed.A valid API key is required to use this endpoint. Obtain your API key from the API Access page in your Pictory dashboard.
API Endpoint
GET https://api.pictory.ai/pictoryapis/v1/jobs/{jobid}
Request Parameters
Path Parameters
uuid
required
The unique identifier (UUID) of the video generation job. This is the
jobId returned by the Generate Video endpoint.Example: "4a09edf9-d071-4847-bda5-8dea913d80fe"Headers
string
required
API key for authentication (starts with
pictai_)Authorization: YOUR_API_KEY
Response
In-Progress Response
Returned while the video is being generated:string
The unique identifier of the video generation job
boolean
true while the job is processingCompleted Response
Returned when the video has been generated successfully:string
The unique identifier of the video generation job
boolean
true when the job has completed successfullyobject
Contains the video generation output.
string
"completed" when the video has been generated successfullystring
Direct download URL for the generated video file (MP4)
string
Duration of the generated video (e.g.,
"8s")number
Width of the generated video in pixels
number
Height of the generated video in pixels
string
URL for the video thumbnail image (JPG)
string
URL for the last frame of the video (PNG). This can be used as a
firstFrameImageUrl in a subsequent generate video request to create a seamless continuation.string
URL for the video preview image (JPG)
number
Number of AI credits consumed for this video generation
Failed Response
Returned when the video generation job has failed:string
The unique identifier of the video generation job
boolean
false when the job has failedobject
Response Examples
{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": true,
"data": {
"status": "in-progress"
}
}
{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": true,
"data": {
"duration": "8s",
"thumbnailImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_thumbnail.jpg",
"lastFrameImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_last_frame.png",
"previewImageUrl": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654_preview.jpg",
"width": 720,
"aiCreditsUsed": 12.8,
"height": 1280,
"url": "https://example.cloudfront.net/videos/user/a1b2c3d4-e5f6-7890-abcd-ef1234567890/d7c6b5a4-e3f2-1098-dcba-fedcba987654.mp4",
"status": "completed"
}
}
{
"job_id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": false,
"data": {
"status": "failed",
"error_code": "5001",
"error_message": "Video generation failed due to an internal error."
}
}
{
"id": "4a09edf9-d071-4847-bda5-8dea913d80fe",
"success": false,
"data": {
"error_code": "5000",
"error_message": "JOB_NOT_FOUND"
}
}
{
"message": "Unauthorized"
}
Status Codes
| Status Code | Description |
|---|---|
| 200 | Request processed successfully. Check the status field in data to determine the job state (in-progress, completed, or failed). |
| 401 | Unauthorized. The API key in the Authorization header is missing or invalid. |
| 404 | Job not found. The provided jobid does not match any existing job. |
| 500 | Internal server error. Retry the request after a brief delay. |
Completed Response Fields
| Field | Description |
|---|---|
url | Direct download link for the generated MP4 video file |
duration | Duration of the generated video (e.g., "8s") |
width | Width of the generated video in pixels |
height | Height of the generated video in pixels |
thumbnailImageUrl | Auto-generated thumbnail image for the video (JPG) |
lastFrameImageUrl | Last frame of the video (PNG), useful for creating video continuations |
previewImageUrl | Preview image for the video (JPG) |
aiCreditsUsed | Number of AI credits consumed for this generation |
Code Examples
Replace
YOUR_API_KEY with your actual API key and use the jobId returned from the Generate Video endpoint.curl --request GET \
--url 'https://api.pictory.ai/pictoryapis/v1/jobs/4a09edf9-d071-4847-bda5-8dea913d80fe' \
--header 'Authorization: YOUR_API_KEY' \
--header 'accept: application/json' | python -m json.tool
import requests
import time
def poll_video_job(api_key, job_id, max_wait=600, poll_interval=15):
"""
Poll for video generation job completion.
Args:
api_key: Your Pictory API key
job_id: The video generation job ID
max_wait: Maximum wait time in seconds (default 10 minutes)
poll_interval: Polling interval in seconds (default 15 seconds)
"""
url = f"https://api.pictory.ai/pictoryapis/v1/jobs/{job_id}"
headers = {
"Authorization": api_key,
"accept": "application/json"
}
start_time = time.time()
while time.time() - start_time < max_wait:
response = requests.get(url, headers=headers)
data = response.json()
if not data.get("success"):
error_data = data.get("data", {})
print(f"Job failed: {error_data.get('error_message', 'Unknown error')}")
return data
status = data.get("data", {}).get("status")
if status == "in-progress":
print("Video generation in progress...")
time.sleep(poll_interval)
continue
if status == "completed":
result = data["data"]
print(f"Video generated successfully!")
print(f"Video URL: {result.get('url')}")
print(f"Duration: {result.get('duration')}")
print(f"Dimensions: {result.get('width')}x{result.get('height')}")
print(f"AI Credits Used: {result.get('aiCreditsUsed')}")
return data
if status == "failed":
error_msg = data["data"].get("error_message", "Unknown error")
print(f"Video generation failed: {error_msg}")
return data
print(f"Unexpected status: {status}")
return data
print("Timeout waiting for video generation")
return None
# Usage
result = poll_video_job("YOUR_API_KEY", "4a09edf9-d071-4847-bda5-8dea913d80fe")
async function pollVideoJob(apiKey, jobId, maxWait = 600000, pollInterval = 15000) {
const url = `https://api.pictory.ai/pictoryapis/v1/jobs/${jobId}`;
const startTime = Date.now();
while (Date.now() - startTime < maxWait) {
const response = await fetch(url, {
method: 'GET',
headers: {
'Authorization': apiKey,
'accept': 'application/json'
}
});
const data = await response.json();
if (!data.success) {
console.log(`Job failed: ${data.data?.error_message || 'Unknown error'}`);
return data;
}
const status = data.data?.status;
if (status === 'in-progress') {
console.log('Video generation in progress...');
await new Promise(resolve => setTimeout(resolve, pollInterval));
continue;
}
if (status === 'completed') {
console.log('Video generated successfully!');
console.log(`Video URL: ${data.data.url}`);
console.log(`Duration: ${data.data.duration}`);
console.log(`Dimensions: ${data.data.width}x${data.data.height}`);
console.log(`AI Credits Used: ${data.data.aiCreditsUsed}`);
return data;
}
if (status === 'failed') {
console.log(`Video generation failed: ${data.data?.error_message}`);
return data;
}
console.log(`Unexpected status: ${status}`);
return data;
}
console.log('Timeout waiting for video generation');
return null;
}
// Usage
const result = await pollVideoJob('YOUR_API_KEY', '4a09edf9-d071-4847-bda5-8dea913d80fe');
<?php
function pollVideoJob($apiKey, $jobId, $maxWait = 600, $pollInterval = 15) {
$url = "https://api.pictory.ai/pictoryapis/v1/jobs/{$jobId}";
$startTime = time();
while (time() - $startTime < $maxWait) {
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: ' . $apiKey,
'accept: application/json'
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (!$data['success']) {
echo "Job failed: " . ($data['data']['error_message'] ?? 'Unknown error') . "\n";
return $data;
}
$status = $data['data']['status'] ?? null;
if ($status === 'in-progress') {
echo "Video generation in progress...\n";
sleep($pollInterval);
continue;
}
if ($status === 'completed') {
echo "Video generated successfully!\n";
echo "Video URL: " . ($data['data']['url'] ?? '') . "\n";
echo "Duration: " . ($data['data']['duration'] ?? '') . "\n";
echo "Dimensions: " . ($data['data']['width'] ?? 0) . "x" . ($data['data']['height'] ?? 0) . "\n";
echo "AI Credits Used: " . ($data['data']['aiCreditsUsed'] ?? 0) . "\n";
return $data;
}
if ($status === 'failed') {
echo "Video generation failed: " . ($data['data']['error_message'] ?? 'Unknown error') . "\n";
return $data;
}
echo "Unexpected status: {$status}\n";
return $data;
}
echo "Timeout waiting for video generation\n";
return null;
}
// Usage
$result = pollVideoJob('YOUR_API_KEY', '4a09edf9-d071-4847-bda5-8dea913d80fe');
?>
package main
import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
func pollVideoJob(apiKey, jobID string, maxWait, pollInterval time.Duration) (map[string]interface{}, error) {
url := fmt.Sprintf("https://api.pictory.ai/pictoryapis/v1/jobs/%s", jobID)
startTime := time.Now()
for time.Since(startTime) < maxWait {
req, _ := http.NewRequest("GET", url, nil)
req.Header.Set("Authorization", apiKey)
req.Header.Set("accept", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
body, _ := io.ReadAll(resp.Body)
resp.Body.Close()
var data map[string]interface{}
json.Unmarshal(body, &data)
success, _ := data["success"].(bool)
if !success {
fmt.Println("Job failed")
return data, nil
}
jobData, _ := data["data"].(map[string]interface{})
status, _ := jobData["status"].(string)
if status == "in-progress" {
fmt.Println("Video generation in progress...")
time.Sleep(pollInterval)
continue
}
if status == "completed" {
fmt.Println("Video generated successfully!")
if videoURL, ok := jobData["url"].(string); ok {
fmt.Printf("Video URL: %s\n", videoURL)
}
if duration, ok := jobData["duration"].(string); ok {
fmt.Printf("Duration: %s\n", duration)
}
return data, nil
}
if status == "failed" {
if msg, ok := jobData["error_message"].(string); ok {
fmt.Printf("Video generation failed: %s\n", msg)
}
return data, nil
}
fmt.Printf("Unexpected status: %s\n", status)
return data, nil
}
return nil, fmt.Errorf("timeout waiting for video generation")
}
func main() {
result, err := pollVideoJob(
"YOUR_API_KEY",
"4a09edf9-d071-4847-bda5-8dea913d80fe",
10*time.Minute,
15*time.Second,
)
if err != nil {
fmt.Println("Error:", err)
return
}
if success, ok := result["success"].(bool); ok && success {
data := result["data"].(map[string]interface{})
if videoURL, ok := data["url"].(string); ok {
fmt.Printf("\nVideo: %s\n", videoURL)
}
}
}
Polling Best Practices
Use a polling interval of 10–30 seconds when checking job status. Polling too frequently may result in rate limiting.
-
Use webhooks when possible. Configure a
webhookURL in the original generate video request to receive automatic notification when the job completes, rather than polling. - Implement timeouts. Set a reasonable maximum wait time. Video generation can take several minutes depending on the model and duration selected.
-
Handle failures gracefully. Inspect
error_codeanderror_messagein failed responses to determine the cause and whether the request can be retried. -
Use the last frame for continuations. The
lastFrameImageUrlfrom a completed job can be passed asfirstFrameImageUrlin a new generate video request to create a seamless video continuation.
Was this page helpful?
