> ## Documentation Index
> Fetch the complete documentation index at: https://docs.babou.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Asset Management

> Upload, organize, and use media assets in your video projects

## 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

<CardGroup cols={2}>
  <Card title="MP4" icon="file-video">
    Most common format, widely supported
  </Card>

  <Card title="MOV" icon="file-video">
    QuickTime format, high quality
  </Card>

  <Card title="AVI" icon="file-video">
    Windows video format
  </Card>

  <Card title="WebM" icon="file-video">
    Web-optimized video format
  </Card>
</CardGroup>

### Image Files

<CardGroup cols={2}>
  <Card title="PNG" icon="file-image">
    Transparent backgrounds supported
  </Card>

  <Card title="JPEG" icon="file-image">
    Compressed photos and graphics
  </Card>

  <Card title="GIF" icon="file-image">
    Animated graphics
  </Card>

  <Card title="WebP" icon="file-image">
    Modern web image format
  </Card>
</CardGroup>

### Audio Files

<CardGroup cols={2}>
  <Card title="MP3" icon="file-audio">
    Most common audio format
  </Card>

  <Card title="WAV" icon="file-audio">
    Uncompressed, high quality
  </Card>

  <Card title="OGG" icon="file-audio">
    Open-source audio format
  </Card>

  <Card title="AAC" icon="file-audio">
    Advanced audio coding
  </Card>
</CardGroup>

<Info>
  **Maximum file size:** 100MB per upload
</Info>

## Uploading Assets

### Single File Upload

<CodeGroup>
  ```bash curl theme={null}
  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"
  ```

  ```typescript TypeScript theme={null}
  import fs from 'fs';

  async function uploadAsset(filePath: string, contentType: string) {
    const fileBuffer = fs.readFileSync(filePath);

    const response = await fetch('https://api.babou.ai/api/v1/assets', {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${process.env.BABOU_API_KEY}`,
        'Content-Type': contentType
      },
      body: fileBuffer
    });

    const asset = await response.json();
    console.log(`✓ Uploaded: ${filePath}`);
    console.log(`  URL: ${asset.url}`);
    console.log(`  ID: ${asset.id}`);

    return asset;
  }

  // Upload an image
  const logo = await uploadAsset('./logo.png', 'image/png');

  // Upload a video
  const intro = await uploadAsset('./intro.mp4', 'video/mp4');
  ```

  ```python Python theme={null}
  import os
  import requests

  def upload_asset(file_path, content_type):
      with open(file_path, 'rb') as file:
          response = requests.post(
              'https://api.babou.ai/api/v1/assets',
              headers={
                  'Authorization': f'Bearer {os.environ["BABOU_API_KEY"]}',
                  'Content-Type': content_type
              },
              data=file
          )

      asset = response.json()
      print(f'✓ Uploaded: {file_path}')
      print(f'  URL: {asset["url"]}')
      print(f'  ID: {asset["id"]}')

      return asset

  # Upload an image
  logo = upload_asset('./logo.png', 'image/png')

  # Upload a video
  intro = upload_asset('./intro.mp4', 'video/mp4')
  ```
</CodeGroup>

### Batch Upload

Upload multiple assets at once:

<CodeGroup>
  ```typescript TypeScript theme={null}
  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`);
  ```

  ```python Python theme={null}
  def upload_assets(files):
      assets = []

      for file_info in files:
          try:
              asset = upload_asset(file_info['path'], file_info['type'])
              assets.append(asset)
          except Exception as e:
              print(f'Failed to upload {file_info["path"]}: {e}')

      return assets

  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'}
  ]

  uploaded_assets = upload_assets(files)
  print(f'✓ Uploaded {len(uploaded_assets)} assets')
  ```
</CodeGroup>

## Managing Assets

### List All Assets

View all your uploaded assets:

```typescript theme={null}
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:

```typescript theme={null}
// 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:

```typescript theme={null}
// 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:

```typescript theme={null}
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

<AccordionGroup>
  <Accordion title="Compress large files" icon="file-zipper">
    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
  </Accordion>

  <Accordion title="Use appropriate formats" icon="file">
    Choose the right format for your use case:

    * **PNG**: Logos, graphics with transparency
    * **JPEG**: Photos, complex images without transparency
    * **MP4**: General video content
    * **MP3**: Background music, voiceovers
  </Accordion>

  <Accordion title="Validate before upload" icon="check">
    ```typescript theme={null}
    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;
    }
    ```
  </Accordion>
</AccordionGroup>

### 2. Track Asset Usage

Keep a record of which assets are used in which projects:

```typescript theme={null}
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:

```typescript theme={null}
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:

```typescript theme={null}
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

```typescript theme={null}
// 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

```typescript theme={null}
// 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

<AccordionGroup>
  <Accordion title="Upload fails with 413 error" icon="triangle-exclamation">
    **Cause:** File exceeds 100MB limit

    **Solution:**

    * Compress the file
    * Split into smaller segments
    * Use a lower resolution/quality
  </Accordion>

  <Accordion title="Asset URL not working in prompts" icon="link">
    **Cause:** Asset still processing or URL expired

    **Solution:**

    * Check asset status: `GET /api/v1/assets/{assetId}`
    * Wait for `state: "ready"`
    * Use fresh URLs (don't cache old URLs)
  </Accordion>

  <Accordion title="Wrong content type error" icon="file">
    **Cause:** Content-Type header doesn't match file

    **Solution:**

    * Verify file extension matches content type
    * Use correct MIME types:
      * PNG: `image/png`
      * JPEG: `image/jpeg`
      * MP4: `video/mp4`
      * MP3: `audio/mpeg`
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Upload Asset" icon="upload" href="/api-reference/assets/upload">
    API reference for asset uploads
  </Card>

  <Card title="Video Creation" icon="video" href="/guides/video-creation-workflow">
    Use assets in your videos
  </Card>

  <Card title="Error Handling" icon="triangle-exclamation" href="/guides/error-handling">
    Handle upload errors
  </Card>
</CardGroup>
