For videos larger than 100MB, use the resumable upload flow. This two-step process generates an upload URL, then your client uploads directly using the TUS protocol.
Step 1: Create Upload URL
POST /v1/gallery/upload/direct
Request Body
Desired filename for the video.
Maximum video duration in seconds. Default: 21600 (6 hours).
How long the upload URL remains valid. Default: 30, max: 360.
Custom metadata to attach to the video.
Bearer token (e.g. Authorization: Bearer YOUR_API_KEY)
Response
The TUS upload URL. Use this with a TUS client to upload the video.
The file ID. Use this to check upload status.
ISO timestamp when the upload URL expires.
TUS protocol version (1.0.0).
Upload instructions including required headers and status check URL.
curl -X POST https://api.voyantcloud.com/v1/gallery/upload/direct \
-H "Authorization: Bearer $VOYANT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"fileName": "conference-recording.mp4",
"expiryMinutes": 60,
"metadata": {"event": "annual-conference-2025"}
}'
{
"uploadUrl": "https://upload.example.com/tus/abc123...",
"fileId": "gal_file_xyz789",
"expiresAt": "2025-01-15T12:30:00.000Z",
"tusVersion": "1.0.0",
"instructions": {
"protocol": "TUS",
"minChunkSize": 5242880,
"headers": {
"Tus-Resumable": "1.0.0"
},
"checkStatus": "/v1/gallery/files/gal_file_xyz789"
}
}
Step 2: Upload the Video
Use any TUS client to upload directly to the uploadUrl. The upload is resumable—if interrupted, it can continue from where it left off.
JavaScript Example (tus-js-client)
import * as tus from "tus-js-client";
const file = document.getElementById("video-input").files[0];
const upload = new tus.Upload(file, {
endpoint: uploadUrl, // From Step 1
retryDelays: [0, 1000, 3000, 5000],
chunkSize: 50 * 1024 * 1024, // 50MB chunks
metadata: {
filename: file.name,
filetype: file.type,
},
onError: (error) => {
console.error("Upload failed:", error);
},
onProgress: (bytesUploaded, bytesTotal) => {
const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2);
console.log(`${percentage}%`);
},
onSuccess: () => {
console.log("Upload complete!");
},
});
upload.start();
Python Example (tuspy)
from tusclient import client
tus_client = client.TusClient(upload_url)
uploader = tus_client.uploader(
"./conference-recording.mp4",
chunk_size=50 * 1024 * 1024, # 50MB chunks
)
uploader.upload()
print("Upload complete!")
Step 3: Check Status
Poll the file endpoint or subscribe to webhooks to know when processing completes.
curl https://api.voyantcloud.com/v1/gallery/files/gal_file_xyz789 \
-H "Authorization: Bearer $VOYANT_API_KEY"
Status Values
| Status | Description |
|---|
pending | Upload URL created, waiting for upload |
processing | Video is being processed |
completed | Ready for playback |
failed | Processing failed |
Webhooks
Subscribe to these events for real-time notifications:
gallery.file.ready — Video processing completed successfully
gallery.file.failed — Video processing failed
For videos under 100MB, you can use the simpler Upload File endpoint with multipart form data.
Upload URLs expire after the specified expiryMinutes. If the URL expires before upload completes, you’ll need to create a new one.