Skip to main content

Video Management

Video Management API

Manage your video library with comprehensive endpoints for listing, retrieving details, and deleting videos. HesedVid provides powerful tools for organizing and maintaining your video content at scale.

Overview

The Video Management API provides:

  • Pagination: Efficient handling of large video libraries
  • Filtering: Search and filter videos by status, date, and metadata
  • Detailed Information: Complete video metadata and encoding details
  • Status Tracking: Real-time processing status updates
  • Soft Deletion: Safe deletion with data preservation for analytics

List Videos

/{orgID}/environments/{envID}/videos

Retrieve a paginated list of videos in an environment with comprehensive filtering and sorting options.

Authentication

All requests require authentication via API key:

X-Api-Key: hv_live_123456789abcdef...

Path Parameters

ParameterTypeRequiredDescription
orgIDstringYesYour organization ID (e.g., org_123456789)
envIDstringYesEnvironment identifier (e.g., prod, staging, dev)

Query Parameters

ParameterTypeDefaultDescription
pageinteger1Page number (1-based)
pageSizeinteger20Items per page (max: 100)
sortBystringcreated_atSort field: created_at, name, duration, status
sortDirstringdescSort direction: asc or desc
statusstring-Filter by status: transcoding, ready, failed
searchstring-Search in video names (case-insensitive)
fromstring-Start date filter (YYYY-MM-DD)
tostring-End date filter (YYYY-MM-DD)

Response

Success Response (200 OK)

{
"body": {
"videos": [
{
"id": "vid_AbCdEfGhIjKlMnOp",
"name": "Product Demo 2024",
"duration": "5:30",
"durationSeconds": 330.5,
"createdAt": "2024-01-15T10:30:00Z",
"thumbnailUrl": "https://worker.hesedvid.com/t/vid_AbCdEfGhIjKlMnOp/320x180.jpg",
"description": "Latest product demonstration video",
"status": "ready",
"served": "1.2K views",
"allowPublicAccess": false,
"videoQuality": "high"
}
],
"pagination": {
"total": 156,
"page": 1,
"pageSize": 20,
"totalPages": 8,
"hasNext": true,
"hasPrevious": false
}
}
}

Response Fields

FieldTypeDescription
idstringUnique video identifier
namestringVideo display name
durationstringHuman-readable duration (e.g., “5:30”)
durationSecondsnumberDuration in seconds
createdAtstringISO 8601 timestamp
thumbnailUrlstringThumbnail image URL
descriptionstringVideo description (if provided)
statusstringProcessing status
servedstringView count summary
allowPublicAccessbooleanPublic access setting
videoQualitystringQuality preset used

Error Responses

StatusErrorDescription
400invalid_page_sizePage size exceeds maximum (100)
401unauthorizedInvalid or missing API key
403forbiddenInsufficient permissions for environment
404environment_not_foundEnvironment doesn’t exist

Example: List Videos

Get Video Details

/{orgID}/videos/{publicID}/details

Retrieve comprehensive information about a specific video, including encoding details, configuration, and processing status.

Path Parameters

ParameterTypeRequiredDescription
orgIDstringYesYour organization ID
publicIDstringYesVideo public ID

Response

Success Response (200 OK)

{
"body": {
"id": "vid_AbCdEfGhIjKlMnOp",
"publicID": "vid_AbCdEfGhIjKlMnOp",
"name": "Product Demo 2024",
"duration": "5:30",
"durationSeconds": 330.5,
"createdAt": "2024-01-15T10:30:00Z",
"thumbnailUrl": "https://worker.hesedvid.com/t/vid_AbCdEfGhIjKlMnOp/1280x720.jpg",
"description": "Latest product demonstration showcasing new features",
"served": "1.2K views",
"status": {
"ready": true,
"transcoding": false,
"failed": false
},
// Configuration
"videoQuality": "high",
"allowPublicAccess": false,
"maxEdgeLength": 1080,
"maxFrameRate": 30,
"pixelFormat": "yuv420p",
"rateControlMode": "variableBitrate",
"twoPassVBREncoding": false,
"compressionRatio": "veryfast",
"audioCodec": "aac",
// Encoding ladder
"encodings": [
{
"key": "1080p",
"shortEdgePixels": 1080,
"shortEdgeIsWidth": false,
"videoStreamBitrate": 5000,
"audioStreamBitrate": 128,
"audioFormat": "aac",
"maxFrameRate": 30,
"pixelFormat": "yuv420p",
"rateControlMode": "variableBitrate",
"twoPassVBREncoding": false,
"compressionRatio": "veryfast"
},
{
"key": "720p",
"shortEdgePixels": 720,
"shortEdgeIsWidth": false,
"videoStreamBitrate": 2500,
"audioStreamBitrate": 128,
"audioFormat": "aac",
"maxFrameRate": 30,
"pixelFormat": "yuv420p",
"rateControlMode": "variableBitrate",
"twoPassVBREncoding": false,
"compressionRatio": "veryfast"
},
{
"key": "480p",
"shortEdgePixels": 480,
"shortEdgeIsWidth": false,
"videoStreamBitrate": 1000,
"audioStreamBitrate": 96,
"audioFormat": "aac",
"maxFrameRate": 30,
"pixelFormat": "yuv420p",
"rateControlMode": "variableBitrate",
"twoPassVBREncoding": false,
"compressionRatio": "veryfast"
}
]
}
}

Response Fields

FieldTypeDescription
idstringInternal video identifier
publicIDstringPublic video identifier (same as id)
namestringVideo display name
durationstringHuman-readable duration
durationSecondsnumberDuration in seconds
createdAtstringISO 8601 timestamp
thumbnailUrlstringBest available thumbnail URL
descriptionstringVideo description
servedstringView count summary
statusobjectProcessing status flags
videoQualitystringQuality preset used
allowPublicAccessbooleanPublic access setting
maxEdgeLengthintegerMaximum resolution setting
maxFrameRatenumberMaximum frame rate setting
pixelFormatstringPixel format used
rateControlModestringRate control mode
twoPassVBREncodingbooleanTwo-pass encoding setting
compressionRatiostringCompression preset
audioCodecstringAudio codec used
encodingsarrayAvailable quality levels

Error Responses

StatusErrorDescription
401unauthorizedInvalid or missing API key
403forbiddenInsufficient permissions for video
404video_not_foundVideo doesn’t exist or is deleted

Example: Get Video Details

Tip

The encoding ladder shows all available quality levels for the video. Use this information to build quality selectors in your player UI and optimize bandwidth usage.

Delete Video

/{orgID}/videos/{videoID}

Permanently delete a video and its associated files. This action uses HesedVid’s enhanced deletion system that preserves analytics data while removing content.

Path Parameters

ParameterTypeRequiredDescription
orgIDstringYesYour organization ID
videoIDstringYesVideo public ID

Request Body (Optional)

{
"reason": "user_request"
}
FieldTypeRequiredDescription
reasonstringNoDeletion reason for audit trail

Deletion Reasons

ReasonDescription
user_requestUser initiated deletion
policy_violationContent policy violation
copyright_claimCopyright infringement
expired_contentContent past retention period
admin_actionAdministrative deletion

Response

Success Response (200 OK)

{
"body": {
"status": "deleted",
"deletedAt": "2024-01-15T11:45:00Z",
"message": "Video deleted successfully. Content will be removed within 24 hours."
}
}
FieldTypeDescription
statusstringDeletion status
deletedAtstringISO 8601 timestamp of deletion
messagestringConfirmation message

Error Responses

StatusErrorDescription
400already_deletedVideo is already deleted
401unauthorizedInvalid or missing API key
403forbiddenInsufficient permissions for video
404video_not_foundVideo doesn’t exist

Example: Delete Video

Caution

Video deletion is permanent. The video is immediately hidden from all interfaces, and files are removed within 24 hours. Analytics data is preserved for billing and reporting purposes.

Video Status Management

Status Types

Videos progress through several states during their lifecycle:

StatusDescriptionPlayableDuration
transcodingVideo is being processedNo2-15 minutes
readyVideo is ready for playbackYesIndefinite
failedProcessing failedNoIndefinite

Status Transitions

graph LR
A[Uploaded] --> B[Transcoding]
B --> C[Ready]
B --> D[Failed]
C --> E[Deleted]
D --> E
D --> F[Retry Processing]
F --> B

Status Polling

For applications that need real-time status updates:

const pollVideoStatus = async (videoID, maxAttempts = 30) => {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const details = await getVideoDetails(videoID);
if (details.status.ready) {
console.log('Video is ready!');
return details;
} else if (details.status.failed) {
console.error('Video processing failed');
return null;
}
// Wait before next poll (exponential backoff)
const delay = Math.min(1000 * Math.pow(2, attempt), 10000);
await new Promise(resolve => setTimeout(resolve, delay));
}
console.log('Status polling timeout');
return null;
};

Filter by Status

// Get only ready videos
const readyVideos = await listVideos({
filters: { status: 'ready' }
});
// Get videos currently processing
const processingVideos = await listVideos({
filters: { status: 'transcoding' }
});

Search by Name

// Search for videos containing "demo"
const demoVideos = await listVideos({
filters: { search: 'demo' }
});
// Case-insensitive search
const productVideos = await listVideos({
filters: { search: 'product' }
});

Date Range Filtering

// Videos from last month
const lastMonth = new Date();
lastMonth.setMonth(lastMonth.getMonth() - 1);
const recentVideos = await listVideos({
filters: {
from: lastMonth.toISOString().split('T')[0],
to: new Date().toISOString().split('T')[0]
}
});

Combined Filters

// Complex filtering example
const filteredVideos = await listVideos({
filters: {
status: 'ready',
search: 'demo',
from: '2024-01-01',
to: '2024-01-31'
},
sortBy: 'created_at',
sortDir: 'desc',
pageSize: 50
});

Pagination Best Practices

Efficient Pagination

const getAllVideos = async (filters = {}) => {
const allVideos = [];
let page = 1;
let hasMore = true;
while (hasMore) {
const result = await listVideos({
page,
pageSize: 100, // Maximum page size
...filters
});
allVideos.push(...result.videos);
hasMore = result.pagination.hasNext;
page++;
}
return allVideos;
};

Infinite Scroll Implementation

const InfiniteVideoList = () => {
const [videos, setVideos] = useState([]);
const [loading, setLoading] = useState(false);
const [hasMore, setHasMore] = useState(true);
const [page, setPage] = useState(1);
const loadMoreVideos = async () => {
if (loading || !hasMore) return;
setLoading(true);
try {
const result = await listVideos({
page,
pageSize: 20
});
setVideos(prev => [...prev, ...result.videos]);
setHasMore(result.pagination.hasNext);
setPage(prev => prev + 1);
} catch (error) {
console.error('Failed to load videos:', error);
} finally {
setLoading(false);
}
};
// Load more when user scrolls to bottom
useEffect(() => {
const handleScroll = () => {
if (window.innerHeight + document.documentElement.scrollTop
>= document.documentElement.offsetHeight - 1000) {
loadMoreVideos();
}
};
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, [page, loading, hasMore]);
return (
<div>
{videos.map(video => (
<VideoCard key={video.id} video={video} />
))}
{loading && <div>Loading...</div>}
</div>
);
};

Error Handling

Comprehensive Error Handling

const handleVideoAPIError = (error, operation) => {
switch (error.status) {
case 400:
console.error(`Bad request for ${operation}:`, error.detail);
break;
case 401:
console.error('Authentication failed - check API key');
break;
case 403:
console.error('Insufficient permissions');
break;
case 404:
console.error('Video or environment not found');
break;
case 429:
console.error('Rate limit exceeded - retry later');
break;
case 500:
console.error('Server error - try again');
break;
default:
console.error(`Unexpected error during ${operation}:`, error);
}
};
// Usage
try {
const videos = await listVideos();
} catch (error) {
handleVideoAPIError(error, 'list videos');
}

Retry Logic

const retryOperation = async (operation, maxRetries = 3) => {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
if (attempt === maxRetries - 1) throw error;
// Exponential backoff
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};
// Usage
const videos = await retryOperation(() => listVideos());

Best Practices

Performance Optimization

  • Implement pagination: Always paginate when listing videos to avoid timeouts with large libraries. Use the maximum page size (100) when possible.

  • Cache video details: Video metadata doesn’t change often. Cache details to reduce API calls and improve performance.

  • Use appropriate filters: Apply filters on the server side rather than filtering large datasets client-side.

  • Implement efficient search: Use the search parameter for name-based filtering rather than downloading all videos.

  • User Experience

  • Handle status polling: When checking processing status, implement exponential backoff to avoid rate limits and reduce server load.

  • Confirm deletions: Always confirm with users before deleting videos as the action is irreversible.

  • Provide feedback: Show loading states, error messages, and success confirmations for all operations.

  • Implement infinite scroll: For large video libraries, use infinite scroll or virtual scrolling to improve performance.

  • Security Considerations

  • Validate permissions: Always check that users have permission to access videos before displaying them.

  • Sanitize search terms: Validate and sanitize search parameters to prevent injection attacks.

  • Rate limit client requests: Implement client-side rate limiting to avoid hitting API limits.

  • Audit deletions: Log all deletion operations with reasons for compliance and debugging.

  • Troubleshooting

    Common Issues

    IssueCauseSolution
    Empty video listWrong environment IDVerify environment ID exists
    Slow loadingLarge page sizeReduce page size or implement pagination
    Search not workingInvalid search syntaxUse simple text search, avoid special characters
    Deletion failsInsufficient permissionsCheck API key permissions
    Status stuckProcessing errorCheck video details for error messages

    Debug Mode

    Enable detailed logging for troubleshooting:

    const debugListVideos = async (options = {}) => {
    console.log('Requesting videos with options:', options);
    const startTime = Date.now();
    const result = await listVideos(options);
    const duration = Date.now() - startTime;
    console.log(`Request completed in ${duration}ms`);
    console.log(`Retrieved ${result.videos.length} videos`);
    console.log(`Total available: ${result.pagination.total}`);
    return result;
    };

    Support

    For additional help:

    • Check our health endpoint GET /health for service issues
    • Review error codes for detailed explanations
    • Contact support with your organization ID and video ID for assistance