Upload Asset
curl --request POST \
--url https://api.example.com/api/v1/assets \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"(raw binary)": {}
}
'import requests
url = "https://api.example.com/api/v1/assets"
payload = { "(raw binary)": {} }
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({'(raw binary)': {}})
};
fetch('https://api.example.com/api/v1/assets', 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.example.com/api/v1/assets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'(raw binary)' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/assets"
payload := strings.NewReader("{\n \"(raw binary)\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/assets")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"(raw binary)\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/assets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"(raw binary)\": {}\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"url": {},
"content_type": "<string>",
"size": {},
"state": "<string>",
"duration": {},
"width": {},
"height": {},
"created_at": "<string>",
"FILE_TOO_LARGE": {},
"UPLOAD_FAILED": {},
"VALIDATION_ERROR": {}
}Assets
Upload Asset
Upload a video, image, or audio file to use in your video projects
POST
/
api
/
v1
/
assets
Upload Asset
curl --request POST \
--url https://api.example.com/api/v1/assets \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"(raw binary)": {}
}
'import requests
url = "https://api.example.com/api/v1/assets"
payload = { "(raw binary)": {} }
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({'(raw binary)': {}})
};
fetch('https://api.example.com/api/v1/assets', 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.example.com/api/v1/assets",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'(raw binary)' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/assets"
payload := strings.NewReader("{\n \"(raw binary)\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/assets")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"(raw binary)\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/assets")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"(raw binary)\": {}\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"name": "<string>",
"url": {},
"content_type": "<string>",
"size": {},
"state": "<string>",
"duration": {},
"width": {},
"height": {},
"created_at": "<string>",
"FILE_TOO_LARGE": {},
"UPLOAD_FAILED": {},
"VALIDATION_ERROR": {}
}Overview
Upload assets (videos, images, audio files) to Babou’s cloud storage. Uploaded assets can be referenced in your video projects and used across multiple chapters.Maximum file size: 100MB per upload
Request
Headers
string
required
Bearer token with your API key:
Bearer sk-bab-your-api-keystring
required
The MIME type of the file being uploaded (e.g.,
video/mp4, image/png, audio/mpeg)Body
Send the raw binary file data as the request body.binary
required
The raw file content
Supported File Types
Video:video/mp4video/quicktime(.mov)video/x-msvideo(.avi)video/webm
image/pngimage/jpegimage/gifimage/webpimage/svg+xml
audio/mpeg(.mp3)audio/wavaudio/oggaudio/aac
Response
string
Unique identifier for the uploaded asset
string
Asset filename
string | null
S3 URL to access the asset (null until upload completes)
string
MIME type of the uploaded file
number | null
File size in bytes
string
Upload state:
uploading, processing, ready, or errornumber | null
Duration in seconds (for video/audio files, null for images)
number | null
Width in pixels (for image/video files)
number | null
Height in pixels (for image/video files)
string
ISO 8601 timestamp of upload
Examples
# Upload an image
curl -X POST https://api.babou.ai/api/v1/assets \
-H "Authorization: Bearer $BABOU_API_KEY" \
-H "Content-Type: image/png" \
--data-binary "@/path/to/image.png"
# Upload a video
curl -X POST https://api.babou.ai/api/v1/assets \
-H "Authorization: Bearer $BABOU_API_KEY" \
-H "Content-Type: video/mp4" \
--data-binary "@/path/to/video.mp4"
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('Asset uploaded:', asset.url);
return asset;
}
// Upload an image
await uploadAsset('./logo.png', 'image/png');
// Upload a video
await uploadAsset('./intro.mp4', 'video/mp4');
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'Asset uploaded: {asset["url"]}')
return asset
# Upload an image
upload_asset('./logo.png', 'image/png')
# Upload a video
upload_asset('./intro.mp4', 'video/mp4')
Response Example
{
"id": "ast_abc123xyz456789012",
"name": "uploaded-file",
"url": "s3://babou-assets/assets/ast_abc123xyz456789012-original",
"content_type": "image/png",
"size": 245678,
"state": "processing",
"duration": null,
"width": null,
"height": null,
"created_at": "2025-12-02T10:00:00Z"
}
Error Responses
413
File exceeds 100MB limit
{
"error": "File size exceeds maximum allowed size of 100MB",
"code": "FILE_TOO_LARGE"
}
500
S3 upload failed
{
"error": "Failed to upload file to storage",
"code": "UPLOAD_FAILED"
}
400
Invalid or missing Content-Type header
{
"error": "Content-Type header is required",
"code": "VALIDATION_ERROR"
}
Best Practices
Check file size before uploading
Check file size before uploading
Validate that your file is under 100MB before making the request to avoid errors:
const stats = fs.statSync(filePath);
if (stats.size > 100 * 1024 * 1024) {
throw new Error('File exceeds 100MB limit');
}
Store asset IDs and URLs
Store asset IDs and URLs
Save the returned
id and url in your database to reference the asset later in your video projects.Use appropriate content types
Use appropriate content types
Always set the correct
Content-Type header matching your file format. This ensures proper processing and display.Handle upload errors gracefully
Handle upload errors gracefully
Implement retry logic for failed uploads, especially for large files that may fail due to network issues.
async function uploadWithRetry(filePath: string, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await uploadAsset(filePath, 'video/mp4');
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(r => setTimeout(r, 1000 * (i + 1)));
}
}
}
Next Steps
Get Asset
Retrieve asset details by ID
List Assets
View all your uploaded assets
Asset Management Guide
Learn how to use assets in your videos