Overview
Upload once. Use everywhere. Assets are the media files (videos, images, audio) you reuse across multiple video projects. Upload your brand assets, product shots, and B-roll, then reference them in prompts.
Supported Asset Types
Video Files
MP4 Most common format, widely supported
MOV QuickTime format, high quality
WebM Web-optimized video format
Image Files
PNG Transparent backgrounds supported
JPEG Compressed photos and graphics
WebP Modern web image format
Audio Files
MP3 Most common audio format
WAV Uncompressed, high quality
OGG Open-source audio format
Maximum file size: 100MB per upload
Uploading Assets
Single File Upload
curl -X POST https://api.babou.ai/api/v1/assets \
-H "Authorization: Bearer $BABOU_API_KEY " \
-H "Content-Type: image/png" \
--data-binary "@./company-logo.png"
Batch Upload
Upload multiple assets at once:
async function uploadAssets ( files : { path : string ; type : string }[]) {
const assets = [];
for ( const file of files ) {
try {
const asset = await uploadAsset ( file . path , file . type );
assets . push ( asset );
} catch ( error ) {
console . error ( `Failed to upload ${ file . path } :` , error );
}
}
return assets ;
}
const files = [
{ path: './logo.png' , type: 'image/png' },
{ path: './background.jpg' , type: 'image/jpeg' },
{ path: './music.mp3' , type: 'audio/mpeg' },
{ path: './intro.mp4' , type: 'video/mp4' }
];
const uploadedAssets = await uploadAssets ( files );
console . log ( `✓ Uploaded ${ uploadedAssets . length } assets` );
Managing Assets
List All Assets
View all your uploaded assets:
const response = await fetch ( 'https://api.babou.ai/api/v1/assets' , {
headers: { 'Authorization' : `Bearer ${ process . env . BABOU_API_KEY } ` }
});
const { assets , pagination } = await response . json ();
console . log ( `Total assets: ${ pagination . total } ` );
assets . forEach ( asset => {
console . log ( `- ${ asset . content_type } : ${ asset . url } ` );
});
Filter by Type
Get specific types of assets:
// Get only images
const images = await fetch (
'https://api.babou.ai/api/v1/assets?contentType=image/png' ,
{
headers: { 'Authorization' : `Bearer ${ process . env . BABOU_API_KEY } ` }
}
). then ( r => r . json ());
// Get only videos
const videos = await fetch (
'https://api.babou.ai/api/v1/assets?contentType=video/mp4' ,
{
headers: { 'Authorization' : `Bearer ${ process . env . BABOU_API_KEY } ` }
}
). then ( r => r . json ());
Organize with Naming Conventions
Use descriptive names in your file paths to keep assets organized:
assets/
├── branding/
│ ├── logo-primary.png
│ ├── logo-white.png
│ └── brand-colors.png
├── products/
│ ├── product-hero.jpg
│ ├── product-detail-1.jpg
│ └── product-detail-2.jpg
├── audio/
│ ├── background-music.mp3
│ └── sound-effects.mp3
└── video/
├── testimonial-1.mp4
└── b-roll.mp4
Using Assets in Videos
Reference in Prompts
Reference uploaded assets in your video prompts:
// Upload logo first
const logo = await uploadAsset ( './logo.png' , 'image/png' );
// Reference in prompt
const prompt = `
Create an intro video:
- Use the company logo at this URL: ${ logo . url }
- Fade in the logo over 2 seconds
- Add tagline below the logo
- Professional corporate style
` ;
await submitPrompt ( projectId , chapterId , prompt );
Asset Library Pattern
Create a reusable asset library:
class AssetLibrary {
private assets : Map < string , string > = new Map ();
async upload ( name : string , filePath : string , contentType : string ) {
const asset = await uploadAsset ( filePath , contentType );
this . assets . set ( name , asset . url );
return asset ;
}
get ( name : string ) : string | undefined {
return this . assets . get ( name );
}
buildPrompt ( template : string ) : string {
let prompt = template ;
for ( const [ name , url ] of this . assets . entries ()) {
prompt = prompt . replace ( `{ ${ name } }` , url );
}
return prompt ;
}
}
// Usage
const library = new AssetLibrary ();
await library . upload ( 'logo' , './logo.png' , 'image/png' );
await library . upload ( 'background' , './bg.jpg' , 'image/jpeg' );
const prompt = library . buildPrompt ( `
Create a video with:
- Logo: {logo}
- Background: {background}
- Smooth animations
` );
await submitPrompt ( projectId , chapterId , prompt );
Best Practices
1. Optimize Before Upload
Keep files under 100MB by compressing them before upload: Images:
Use tools like TinyPNG, ImageOptim, or Squoosh
Convert to WebP for smaller file sizes
Resize to appropriate dimensions
Videos:
Use HandBrake or FFmpeg to compress
Target reasonable bitrates (e.g., 5-10 Mbps for 1080p)
Consider lower resolutions if appropriate
Audio:
Use 128-320 kbps for MP3
Consider mono instead of stereo for voice
Trim silence from beginning and end
function validateAsset ( filePath : string , maxSize = 100 * 1024 * 1024 ) {
const stats = fs . statSync ( filePath );
if ( stats . size > maxSize ) {
throw new Error ( `File ${ filePath } exceeds 100MB limit` );
}
const ext = path . extname ( filePath ). toLowerCase ();
const allowedExts = [ '.png' , '.jpg' , '.jpeg' , '.gif' , '.mp4' , '.mov' , '.mp3' , '.wav' ];
if ( ! allowedExts . includes ( ext )) {
throw new Error ( `Unsupported file type: ${ ext } ` );
}
return true ;
}
2. Track Asset Usage
Keep a record of which assets are used in which projects:
interface AssetUsage {
assetId : string ;
assetUrl : string ;
projectIds : string [];
uploadedAt : string ;
}
const assetRegistry : Map < string , AssetUsage > = new Map ();
function trackAssetUsage ( assetId : string , projectId : string ) {
const usage = assetRegistry . get ( assetId ) || {
assetId ,
assetUrl: '' ,
projectIds: [],
uploadedAt: new Date (). toISOString ()
};
if ( ! usage . projectIds . includes ( projectId )) {
usage . projectIds . push ( projectId );
}
assetRegistry . set ( assetId , usage );
}
3. Implement Retry Logic
Handle upload failures gracefully:
async function uploadWithRetry (
filePath : string ,
contentType : string ,
maxRetries = 3
) {
for ( let attempt = 0 ; attempt < maxRetries ; attempt ++ ) {
try {
return await uploadAsset ( filePath , contentType );
} catch ( error : any ) {
if ( attempt === maxRetries - 1 ) throw error ;
console . log ( `Upload failed, retrying ( ${ attempt + 1 } / ${ maxRetries } )...` );
await new Promise ( r => setTimeout ( r , 1000 * ( attempt + 1 )));
}
}
}
4. Clean Up Unused Assets
Periodically review and delete unused assets:
async function findUnusedAssets () {
const { assets } = await fetch (
'https://api.babou.ai/api/v1/assets' ,
{
headers: { 'Authorization' : `Bearer ${ process . env . BABOU_API_KEY } ` }
}
). then ( r => r . json ());
const oneMonthAgo = new Date ();
oneMonthAgo . setMonth ( oneMonthAgo . getMonth () - 1 );
const unused = assets . filter ( asset => {
const createdAt = new Date ( asset . created_at );
const isOld = createdAt < oneMonthAgo ;
const isUnused = ! assetRegistry . has ( asset . id );
return isOld && isUnused ;
});
console . log ( `Found ${ unused . length } unused assets` );
return unused ;
}
Common Workflows
Workflow 1: Branded Content
// Upload brand assets once
const brandAssets = {
logo: await uploadAsset ( './brand/logo.png' , 'image/png' ),
colors: await uploadAsset ( './brand/colors.png' , 'image/png' ),
font: await uploadAsset ( './brand/font-sample.png' , 'image/png' )
};
// Reuse in multiple videos
function createBrandedPrompt ( content : string ) {
return `
${ content }
Branding:
- Logo: ${ brandAssets . logo . url }
- Use brand colors from: ${ brandAssets . colors . url }
- Typography reference: ${ brandAssets . font . url }
` ;
}
// Use in different projects
await submitPrompt (
project1Id ,
chapterId ,
createBrandedPrompt ( 'Create product intro' )
);
await submitPrompt (
project2Id ,
chapterId ,
createBrandedPrompt ( 'Create tutorial video' )
);
Workflow 2: Template Library
// Upload template assets
const templates = {
intro: {
background: await uploadAsset ( './templates/intro-bg.mp4' , 'video/mp4' ),
music: await uploadAsset ( './templates/intro-music.mp3' , 'audio/mpeg' )
},
outro: {
background: await uploadAsset ( './templates/outro-bg.mp4' , 'video/mp4' ),
music: await uploadAsset ( './templates/outro-music.mp3' , 'audio/mpeg' )
}
};
// Apply templates
function applyTemplate ( type : 'intro' | 'outro' , customContent : string ) {
const template = templates [ type ];
return `
${ customContent }
Use these template assets:
- Background: ${ template . background . url }
- Music: ${ template . music . url }
` ;
}
Troubleshooting
Upload fails with 413 error
Cause: File exceeds 100MB limitSolution:
Compress the file
Split into smaller segments
Use a lower resolution/quality
Asset URL not working in prompts
Cause: Asset still processing or URL expiredSolution:
Check asset status: GET /api/v1/assets/{assetId}
Wait for state: "ready"
Use fresh URLs (don’t cache old URLs)
Cause: Content-Type header doesn’t match fileSolution:
Verify file extension matches content type
Use correct MIME types:
PNG: image/png
JPEG: image/jpeg
MP4: video/mp4
MP3: audio/mpeg
Next Steps