Overview
Update an existing project by sending the complete updated project object. This endpoint allows you to modify scene visuals, subtitle text content, scene settings, and other project attributes. The entire project object must be included in the request—partial updates are not supported.
Complete Object Required : You must send the entire project object in the request body, even if you’re only changing a few fields. Omitting fields may result in data loss or project corruption.
You need a valid API key to use this endpoint. Get your API key from the API Access page in your Pictory dashboard.
API Endpoint
PUT https://api.pictory.ai/pictoryapis/v2/projects/{projectid}
Request Parameters
Path Parameters
The unique identifier of the project to update. Can be either a string (for v3 schema projects) or an integer (for v2 schema and earlier projects). Example: 20251222191648030d7df02f5b4054d4ca8831f1369459e25
API key for authentication (starts with pictai_) Authorization: YOUR_API_KEY
Must be set to application/json Content-Type: application/json
Body Parameters
The request body must contain the complete project object. Below are the key fields you can safely modify:
Array of scene objects representing the video storyboard Show Scene object properties
Safe to modify : URL to the background image or video for this sceneExample: "https://your-media-url.com/video.mp4"
Safe to modify : The complete subtitle text for this scene (supports HTML formatting)Example: "New sentence with <strong>bold</strong> words."
Safe to modify : Array of text line objects for subtitle displayPlain text version of the subtitle line
HTML-formatted version of the subtitle line
Safe to modify : Scene-specific playback and display settingsEnable or disable zoom/pan effect on static images
Mute the background video’s original audio
Loop the background video if it’s shorter than the scene duration
Hide subtitle text for this scene
Audio playback speed percentage (100 = normal speed)
Background video volume level (0-100)
What You Can Safely Update
Field : scenes[n].imageReplace the background image or video URL for a specific scene. {
"scenes" : [
{
"image" : "https://your-new-media-url.com/video.mp4"
}
]
}
Fields : scenes[n].sentence, scenes[n].lines[m].text, scenes[n].lines[m].htmlUpdate the displayed subtitle or on-screen text. {
"scenes" : [
{
"sentence" : "New sentence with <strong>bold</strong> words." ,
"lines" : [
{
"text" : "New sentence with bold words." ,
"html" : "New sentence with <strong>bold</strong> words."
}
]
}
]
}
Field : scenes[n].settingsControl playback behavior, audio options, and text visibility. {
"scenes" : [
{
"settings" : {
"imageZoomPan" : false ,
"muteClipAudio" : false ,
"loopVideo" : true ,
"hideText" : false
}
}
]
}
Fields to Avoid Modifying
Do Not Modify These Fields unless you fully understand their structure and dependencies:
uuid - Unique identifiers for scenes and elements
imageMetadata - System-generated metadata
voiceOverAudioIds - Internal audio reference IDs
assetResponseId - Asset tracking identifiers
schemaVersion - Project schema version
inProgress - Processing status flag
Other system-generated or internal fields
Modifying these fields without proper understanding can cause project corruption or rendering failures.
Response
Indicates whether the update was successful
Confirmation message about the update
The updated project object with all current values
Response Examples
200 - Success
400 - Bad Request
401 - Unauthorized
404 - Not Found
{
"success" : true ,
"message" : "Project updated successfully" ,
"project" : {
"projectName" : "Updated Project Name" ,
"scenes" : [
{
"image" : "https://new-media-url.com/video.mp4" ,
"sentence" : "Updated subtitle text" ,
"settings" : {
"imageZoomPan" : false ,
"muteClipAudio" : true
}
}
]
}
}
Code Examples
Replace YOUR_API_KEY with your actual API key that starts with pictai_
# First, get the current project
PROJECT_DATA = $( curl --request GET \
--url 'https://api.pictory.ai/pictoryapis/v2/projects/YOUR_PROJECT_ID' \
--header 'Authorization: YOUR_API_KEY' \
--header 'accept: application/json' )
# Modify the project data (using jq)
UPDATED_DATA = $( echo $PROJECT_DATA | jq '.projectName = "Updated Name"' )
# Send the update
curl --request PUT \
--url 'https://api.pictory.ai/pictoryapis/v2/projects/YOUR_PROJECT_ID' \
--header 'Authorization: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data " $UPDATED_DATA "
Usage Notes
Always Retrieve Before Update : Always fetch the current project state using the GET endpoint before making modifications. This ensures you have the complete object with all required fields.
Complete Object Required : Even if you only want to change one field, you must send the entire project object. Omitting fields will cause them to be removed from the project.
Test Changes First : When making significant updates, consider testing on a copy of the project first to ensure your modifications don’t cause rendering issues.
Common Use Cases
1. Update Scene Background Visual
Replace the background media for a specific scene:
import requests
def update_scene_background ( project_id , scene_index , new_media_url , api_key ):
"""
Update the background visual for a specific scene
"""
headers = { "Authorization" : api_key, "Content-Type" : "application/json" }
# Get current project
get_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
response = requests.get(get_url, headers = headers)
project = response.json()
# Update the scene background
if scene_index < len (project.get( 'scenes' , [])):
project[ 'scenes' ][scene_index][ 'image' ] = new_media_url
print ( f "Updated scene { scene_index } background to: { new_media_url } " )
# Send update
put_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
update_response = requests.put(put_url, json = project, headers = headers)
result = update_response.json()
if result.get( 'success' ):
print ( "Project updated successfully" )
return result
else :
print ( f "Update failed: { result.get( 'message' ) } " )
return None
else :
print ( f "Scene index { scene_index } out of range" )
return None
# Example usage
update_scene_background(
"YOUR_PROJECT_ID" ,
0 , # First scene
"https://your-media-url.com/new-video.mp4" ,
"YOUR_API_KEY"
)
2. Update Subtitle Text
Modify subtitle text for one or more scenes:
async function updateSubtitles ( projectId , sceneUpdates , apiKey ) {
const headers = {
'Authorization' : ` ${ apiKey } ` ,
'Content-Type' : 'application/json'
};
// Get current project
const getResponse = await fetch (
`https://api.pictory.ai/pictoryapis/v2/projects/ ${ projectId } ` ,
{ headers }
);
const project = await getResponse . json ();
// Update subtitles
sceneUpdates . forEach (({ sceneIndex , newText }) => {
if ( sceneIndex < project . scenes . length ) {
// Update both plain text and HTML versions
project . scenes [ sceneIndex ]. sentence = newText ;
project . scenes [ sceneIndex ]. lines = [
{
text: newText . replace ( /< [ ^ > ] * >/ g , '' ), // Strip HTML
html: newText
}
];
console . log ( `Updated scene ${ sceneIndex } subtitle` );
}
});
// Send update
const updateResponse = await fetch (
`https://api.pictory.ai/pictoryapis/v2/projects/ ${ projectId } ` ,
{
method: 'PUT' ,
headers ,
body: JSON . stringify ( project )
}
);
const result = await updateResponse . json ();
return result ;
}
// Example usage
const updates = [
{ sceneIndex: 0 , newText: 'Welcome to our <strong>amazing</strong> product!' },
{ sceneIndex: 1 , newText: 'Here are the <em>key features</em>.' }
];
const result = await updateSubtitles ( 'YOUR_PROJECT_ID' , updates , 'YOUR_API_KEY' );
console . log ( 'Update result:' , result );
3. Bulk Update Scene Settings
Apply settings changes to multiple scenes:
def update_scene_settings ( project_id , settings_updates , api_key ):
"""
Apply settings to multiple scenes
settings_updates: dict with scene indices as keys and settings as values
Example: {
0: {"muteClipAudio": True, "loopVideo": True},
2: {"hideText": True}
}
"""
headers = { "Authorization" : api_key, "Content-Type" : "application/json" }
# Get current project
get_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
response = requests.get(get_url, headers = headers)
project = response.json()
# Update scene settings
for scene_index, new_settings in settings_updates.items():
if scene_index < len (project.get( 'scenes' , [])):
# Merge new settings with existing settings
current_settings = project[ 'scenes' ][scene_index].get( 'settings' , {})
current_settings.update(new_settings)
project[ 'scenes' ][scene_index][ 'settings' ] = current_settings
print ( f "Updated settings for scene { scene_index } " )
# Send update
put_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
update_response = requests.put(put_url, json = project, headers = headers)
return update_response.json()
# Example usage
settings = {
0 : { "muteClipAudio" : True , "loopVideo" : True },
1 : { "imageZoomPan" : False },
2 : { "hideText" : True , "muteClipAudio" : True }
}
result = update_scene_settings( "YOUR_PROJECT_ID" , settings, "YOUR_API_KEY" )
print ( f "Update successful: { result.get( 'success' ) } " )
Change project name and playback settings:
async function updateProjectMetadata ( projectId , metadata , apiKey ) {
const headers = {
'Authorization' : ` ${ apiKey } ` ,
'Content-Type' : 'application/json'
};
// Get current project
const getResponse = await fetch (
`https://api.pictory.ai/pictoryapis/v2/projects/ ${ projectId } ` ,
{ headers }
);
const project = await getResponse . json ();
// Update metadata
if ( metadata . name ) project . projectName = metadata . name ;
if ( metadata . audioSpeed ) project . audioSpeed = metadata . audioSpeed ;
if ( metadata . videoVolume !== undefined ) project . videoVolume = metadata . videoVolume ;
console . log ( 'Updated project metadata:' , metadata );
// Send update
const updateResponse = await fetch (
`https://api.pictory.ai/pictoryapis/v2/projects/ ${ projectId } ` ,
{
method: 'PUT' ,
headers ,
body: JSON . stringify ( project )
}
);
return await updateResponse . json ();
}
// Example usage
const metadata = {
name: 'My Updated Project' ,
audioSpeed: 105 ,
videoVolume: 80
};
const result = await updateProjectMetadata ( 'YOUR_PROJECT_ID' , metadata , 'YOUR_API_KEY' );
console . log ( 'Result:' , result );
5. Replace All Scene Backgrounds
Replace backgrounds for all scenes at once:
def replace_all_backgrounds ( project_id , media_urls , api_key ):
"""
Replace background media for all scenes
media_urls: list of URLs, one for each scene
"""
headers = { "Authorization" : api_key, "Content-Type" : "application/json" }
# Get current project
get_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
response = requests.get(get_url, headers = headers)
project = response.json()
scenes = project.get( 'scenes' , [])
if len (media_urls) != len (scenes):
print ( f "Warning: { len (media_urls) } URLs provided for { len (scenes) } scenes" )
return None
# Update all scene backgrounds
for i, url in enumerate (media_urls):
scenes[i][ 'image' ] = url
print ( f "Scene { i } : { url } " )
project[ 'scenes' ] = scenes
# Send update
put_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
update_response = requests.put(put_url, json = project, headers = headers)
return update_response.json()
# Example usage
new_backgrounds = [
"https://media-url.com/scene1.mp4" ,
"https://media-url.com/scene2.mp4" ,
"https://media-url.com/scene3.mp4"
]
result = replace_all_backgrounds( "YOUR_PROJECT_ID" , new_backgrounds, "YOUR_API_KEY" )
if result and result.get( 'success' ):
print ( "All backgrounds updated successfully" )
6. Safe Update with Validation
Implement validation before updating:
import copy
def safe_update_project ( project_id , update_function , api_key ):
"""
Safely update project with validation
update_function: function that takes project dict and modifies it
"""
headers = { "Authorization" : api_key, "Content-Type" : "application/json" }
# Get current project
get_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
response = requests.get(get_url, headers = headers)
if response.status_code != 200 :
print ( "Failed to fetch project" )
return None
original_project = response.json()
updated_project = copy.deepcopy(original_project)
# Apply updates
try :
update_function(updated_project)
except Exception as e:
print ( f "Error applying updates: { e } " )
return None
# Validate critical fields are present
required_fields = [ 'projectName' , 'scenes' , 'schemaVersion' ]
for field in required_fields:
if field not in updated_project:
print ( f "Critical field ' { field } ' missing after update" )
return None
# Send update
put_url = f "https://api.pictory.ai/pictoryapis/v2/projects/ { project_id } "
update_response = requests.put(put_url, json = updated_project, headers = headers)
result = update_response.json()
if result.get( 'success' ):
print ( "Project updated successfully" )
else :
print ( f "Update failed: { result.get( 'message' ) } " )
return result
# Example usage
def my_updates ( project ):
"""Define your updates here"""
project[ 'projectName' ] = 'New Name'
project[ 'audioSpeed' ] = 95
# Mute audio for first scene
if project[ 'scenes' ]:
project[ 'scenes' ][ 0 ][ 'settings' ][ 'muteClipAudio' ] = True
result = safe_update_project( "YOUR_PROJECT_ID" , my_updates, "YOUR_API_KEY" )
Best Practices
Safety Guidelines
Always Fetch First : Get the current project state before making any modifications
Preserve All Fields : Include all fields in the update request, even if unchanged
Test on Copies : Test significant changes on duplicate projects first
Validate Before Sending : Ensure all required fields are present before updating
Keep Backups : Save the original project state before applying updates
Common Pitfalls to Avoid
❌ Partial Updates : Sending only modified fields will delete other fields
❌ Missing Required Fields : Omitting critical fields causes project corruption
❌ Invalid Values : Using incorrect data types or formats for fields
❌ Modifying System Fields : Changing internal IDs or metadata
❌ No Validation : Updating without checking the project state first
Batch multiple changes in a single update request
Minimize the frequency of updates during active editing
Cache the project object locally during editing sessions
Only fetch/update when necessary to reduce API calls