Video Generation
The Scenario API extends beyond static image generation to support dynamic content creation, including video. These advanced functionalities often involve longer processing times and utilize a flexible "custom" endpoint, requiring a job polling mechanism to retrieve the final results. This guide will explain how to initiate video , monitor their progress, and retrieve the completed assets.
The Custom Endpoint
For specialized generation tasks like video, the Scenario API provides a versatile custom endpoint. This endpoint allows you to interact with specific models tailored for these complex outputs.
POST https://api.cloud.scenario.com/v1/generate/custom/{modelId}
- API Reference
Where {modelId}
is the identifier for the specific video generation model you wish to use (e.g., model_kling-v2-1
for Kling 2.1 video model). Available models ID are here: https://docs.scenario.com/docs/video-models-parameters-reference
Request Body for Custom Generation
The payload for the custom endpoint will vary depending on the modelId
and the type of generation (video or 3D). However, common parameters often include:
Parameter | Type | Description |
---|---|---|
image | string | The first frame of your model. |
prompt | string | A textual description to guide the generation. |
steps | integer | The number of processing steps for the generation. Higher values can lead to higher quality but longer processing times. |
guidanceScale | number | Controls how closely the generation follows the prompt. |
duration | number | The desired duration of the video in seconds. |
fps | integer | Frames per second for the video output. |
Note: To find the correct list of parameters for a specific model you can spy network requests. You can also have the parameters of all video models here: https://docs.scenario.com/docs/video-models-parameters-reference
Job Polling: Retrieving Asynchronous Results
Unlike instant image generation, video and 3D model generation are asynchronous processes. This means that when you make a request to the custom endpoint, you will receive a jobId
immediately, but the actual generation will happen in the background. You then need to periodically poll a separate endpoint to check the status and retrieve the final asset.
Polling Endpoint
GET https://api.cloud.scenario.com/v1/jobs/{jobId}
- API Reference
Polling Response
The response from the polling endpoint will contain the current status of your job. You should continue polling until the status
field indicates success
or failed
.
{
"job": {
"jobId": "job_abc123def456",
"status": "processing", // Can be \"queued\", \"processing\", \"success\", \"failed\", \"canceled\"
"progress": 0.5, // Optional: progress percentage
"metadata": {
"assetIds": []
}
},
"creativeUnitsCost": 5
}
Once the status
is success
, the metadata.assetIds
field will contain the IDs to your generated video or 3D model assets.
Code Examples: Video Generation with VEO3
This example demonstrates initiating a video generation and then polling for the result.
Initial Request (cURL)
curl -X POST \
-u "YOUR_API_KEY:YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-d
\"{"prompt":"A lone skateboarder, silhouetted against the golden burnish of a late afternoon sun, carves gracefully along a winding, empty coastal road high above the shimmering sea. Every turn of their board kicks up subtle puffs of dust and pigment from the sunbaked asphalt, while their loose shirt flutters dynamically behind them. In the distance, waves crash gently against rocky cliffs and wind-whipped wildflowers shudder in the breeze. Soft, diffused sunlight glances off chrome wheels and the skateboard’s deck, casting long, painterly shadows that stretch toward the ocean’s horizon. The camera sweeps alongside in a smooth tracking shot at low angle, occasionally veering ahead for a fleeting over-the-shoulder glimpse of endless blue water, before dropping back to capture the kinetic grace of each turn. Audio: the rhythmic rumble of urethane wheels, the hush of wind, distant gulls, and a faint, dreamy indie guitar melody. The tone is wistful, freeing, and full of sunlit nostalgia.",
"generateAudio":true,
"aspectRatio":"16:9",
"duration":8
}\" \
https://api.cloud.scenario.com/v1/generate/custom/model_veo3?projectId=yourprojectid
Python
import requests
import time
api_key = "YOUR_API_KEY"
api_secret = "YOUR_API_SECRET"
project_id = "model_veo3"
# Step 1: Initiate Video Generation
custom_video_model_id = "your_video_model_id" # Replace with actual video model ID
initial_url = f"https://api.cloud.scenario.com/v1/generate/custom/{custom_video_model_id}?projectId={project_id}"
headers = {"Content-Type": "application/json"}
payload = {
"prompt":"A lone skateboarder, silhouetted against the golden burnish of a late afternoon sun, carves gracefully along a winding, empty coastal road high above the shimmering sea. Every turn of their board kicks up subtle puffs of dust and pigment from the sunbaked asphalt, while their loose shirt flutters dynamically behind them. In the distance, waves crash gently against rocky cliffs and wind-whipped wildflowers shudder in the breeze. Soft, diffused sunlight glances off chrome wheels and the skateboard’s deck, casting long, painterly shadows that stretch toward the ocean’s horizon. The camera sweeps alongside in a smooth tracking shot at low angle, occasionally veering ahead for a fleeting over-the-shoulder glimpse of endless blue water, before dropping back to capture the kinetic grace of each turn. Audio: the rhythmic rumble of urethane wheels, the hush of wind, distant gulls, and a faint, dreamy indie guitar melody. The tone is wistful, freeing, and full of sunlit nostalgia.",
"generateAudio":true,
"aspectRatio":"16:9",
"duration":8
}
print("Initiating video generation...")
initial_response = requests.post(initial_url, headers=headers, json=payload, auth=(api_key, api_secret))
if initial_response.status_code == 200:
initial_data = initial_response.json()
job_id = initial_data.get("job").get("jobId")
if job_id:
print(f"Video generation job initiated. Job ID: {job_id}")
# Step 2: Poll for Job Status
polling_url = f"https://api.scenario.com/v1/jobs/{job_id}"
status = "queued"
while status not in ["success", "failure", "canceled"]:
print(f"Polling job {job_id}... Current status: {status}")
time.sleep(3) # Wait for 3 seconds before polling again
polling_response = requests.get(polling_url, auth=(api_key, api_secret))
if polling_response.status_code == 200:
polling_data = polling_response.json()
status = polling_data.get("job").get("status")
progress = polling_data.get("job").get("progress", 0) * 100
print(f"Progress: {progress:.2f}%")
if status == "success":
asset_ids = polling_data.get("job").get("metadata").get("assetIds", [])
print(f"Video generation completed! Asset IDs: {asset_ids}")
elif status in ["failure", "canceled"]:
print(f"Video generation failed or canceled: {polling_data.get("job").get("error")}")
else:
print(f"Error polling job status: {polling_response.status_code} - {polling_response.text}")
break
else:
print("Error: No jobId returned in the initial response.")
else:
print(f"Error initiating video generation: {initial_response.status_code} - {initial_response.text}")
Node.js
const fetch = require("node-fetch");
const apiKey = "YOUR_API_KEY";
const apiSecret = "YOUR_API_SECRET";
const projectId = "yourprojectid";
const credentials = Buffer.from(`${apiKey}:${apiSecret}`).toString("base64");
async function generateVideo() {
const customVideoModelId = "your_video_model_id"; // Replace with actual video model ID
const initialUrl = `https://api.cloud.scenario.com/v1/generate/custom/${customVideoModelId}?projectId=${projectId}`;
const headers = {
"Content-Type": "application/json",
Authorization: `Basic ${credentials}`,
};
const payload = {
prompt: "a futuristic city with flying cars, cinematic, 4k",
duration: 5,
fps: 24,
};
console.log("Initiating video generation...");
try {
const initialResponse = await fetch(initialUrl, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
});
const initialData = await initialResponse.json();
if (initialResponse.ok) {
const jobId = initialData.job.jobId;
if (jobId) {
console.log(`Video generation job initiated. Job ID: ${jobId}`);
const pollingUrl = `https://api.scenario.com/v1/jobs/${jobId}`;
let status = "queued";
while (!["success", "failure", "canceled"].includes(status)) {
console.log(`Polling job ${jobId}... Current status: ${status}`);
await new Promise(resolve => setTimeout(resolve, 3000)); // Wait for 3 seconds
const pollingResponse = await fetch(pollingUrl, {
headers: { Authorization: `Basic ${credentials}` },
});
const pollingData = await pollingResponse.json();
if (pollingResponse.ok) {
status = pollingData.job.status;
const progress = (pollingData.job.progress || 0) * 100;
console.log(`Progress: ${progress.toFixed(2)}%`);
if (status === "success") {
const asset_ids = polling_data.get("job").get("metadata").get("assetIds", []);
console.log("Video generation completed! Asset IDs:", asset_ids);
} else if (["failure", "canceled"].includes(status)) {
console.error(`Video generation failed or canceled: ${pollingData.job.error}`);
}
} else {
console.error(`Error polling job status: ${pollingResponse.status} - ${JSON.stringify(pollingData)}`);
break;
}
}
} else {
console.error("Error: No jobId returned in the initial response.");
}
} else {
console.error(`Error initiating video generation: ${initialResponse.status} - ${JSON.stringify(initialData)}`);
}
} catch (error) {
console.error("Network or other error:", error);
}
}
generateVideo();
Updated about 12 hours ago