Thumbnails
Thumbnails API
Generate custom thumbnails from your videos at any timestamp. HesedVid’s thumbnail generation system allows you to create high-quality thumbnails in any resolution, perfect for video previews, galleries, and user interfaces.
Overview
The Thumbnails API provides two main functionalities:
- Generate Custom Thumbnails: Create thumbnails at specific timestamps with custom dimensions
- Get Best Available Thumbnail: Retrieve the highest quality thumbnail for a video
- Check Generation Status: Monitor thumbnail generation progress
Generate Custom Thumbnail
/{orgID}/videos/{publicID}/thumbnails
Generate a custom thumbnail from a specific timestamp in your video.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgID | string | Yes | Your organization’s unique identifier |
publicID | string | Yes | The public ID of the video asset |
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
width | int32 | Yes | Thumbnail width in pixels (1-4096) |
height | int32 | Yes | Thumbnail height in pixels (1-4096) |
timestampMs | int32 | Yes | Timestamp in milliseconds (0 to video duration) |
Response
{ "body": { "jobId": "thumb_job_123456789abcdef", "url": "https://worker.hesedvid.com/pubvid_AbCdEf/thumbnails/custom/12000_320x180.webp", "status": "pending" }}Example Request
curl -X POST "https://api.hesedvid.com/v1/api/org_123456789/videos/pubvid_AbCdEf/thumbnails" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz" \ -H "Content-Type: application/json" \ -d '{ "width": 320, "height": 180, "timestampMs": 12000 }'const generateThumbnail = async () => { const response = await fetch('https://api.hesedvid.com/v1/api/org_123456789/videos/pubvid_AbCdEf/thumbnails', { method: 'POST', headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz', 'Content-Type': 'application/json' }, body: JSON.stringify({ width: 320, height: 180, timestampMs: 12000 }) }); return response.json();};import requests
def generate_thumbnail(): url = "https://api.hesedvid.com/v1/api/org_123456789/videos/pubvid_AbCdEf/thumbnails" headers = { "X-Api-Key": "hv_live_123456789abcdefghijklmnopqrstuvwxyz", "Content-Type": "application/json" } data = { "width": 320, "height": 180, "timestampMs": 12000 } response = requests.post(url, headers=headers, json=data) return response.json()Get Best Available Thumbnail
/{orgID}/videos/{publicID}/thumbnail
Retrieve the highest quality thumbnail available for a video.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
orgID | string | Yes | Your organization’s unique identifier |
publicID | string | Yes | The public ID of the video asset |
Response
{ "body": { "url": "https://worker.hesedvid.com/pubvid_AbCdEf/thumbnails/custom/5000_640x360.webp", "available": true, "width": 640, "height": 360 }}Example Request
curl -X GET "https://api.hesedvid.com/v1/api/org_123456789/videos/pubvid_AbCdEf/thumbnail" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"const getThumbnail = async () => { const response = await fetch('https://api.hesedvid.com/v1/api/org_123456789/videos/pubvid_AbCdEf/thumbnail', { headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz' } }); return response.json();};Check Thumbnail Generation Status
/thumbnails/{jobID}
Monitor the progress of thumbnail generation jobs.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
jobID | string | Yes | The job ID returned from thumbnail generation |
Response
{ "body": { "status": "completed", "url": "https://worker.hesedvid.com/pubvid_AbCdEf/thumbnails/custom/12000_320x180.webp" }}Job Status Values
| Status | Description |
|---|---|
pending | Thumbnail generation is queued |
processing | Thumbnail is being generated |
completed | Thumbnail is ready and URL is available |
failed | Generation failed (check error logs) |
Example Request
curl -X GET "https://api.hesedvid.com/v1/api/thumbnails/thumb_job_123456789abcdef" \ -H "X-Api-Key: hv_live_123456789abcdefghijklmnopqrstuvwxyz"const checkThumbnailStatus = async (jobId) => { const response = await fetch(`https://api.hesedvid.com/v1/api/thumbnails/${jobId}`, { headers: { 'X-Api-Key': 'hv_live_123456789abcdefghijklmnopqrstuvwxyz' } }); return response.json();};Thumbnail Generation Process
How It Works
- Request Submission: Submit thumbnail generation request with dimensions and timestamp
- Job Creation: System creates a background job and returns job ID
- Processing: Worker processes the video frame at specified timestamp
- Storage: Generated thumbnail is stored in WebP format
- Delivery: Thumbnail is served via CDN for fast access
Supported Formats
- Output Format: WebP (optimized for web delivery)
- Dimensions: 1x1 to 4096x4096 pixels
- Aspect Ratios: Any aspect ratio supported
Performance Considerations
- Generation Time: Typically 2-10 seconds depending on video complexity
- Concurrent Jobs: Up to 5 thumbnail jobs per organization
- Caching: Generated thumbnails are cached indefinitely
- CDN Delivery: Thumbnails served via global CDN for fast access
Best Practices
Thumbnail Dimensions
- Video Galleries: 320x180 (16:9) or 240x135 (16:9)
- Social Media: 1200x630 (Facebook) or 1200x675 (Twitter)
- Mobile Apps: 640x360 or 480x270
- High Quality: 1920x1080 for detailed previews
Timestamp Selection
- Video Start: Use
0for opening frame - Key Moments: Extract frames at important scenes
- Midpoint: Use
videoDurationMs / 2for middle frame - Custom: Choose specific timestamps for branded content
Error Handling
const generateThumbnailWithRetry = async (videoId, options, maxRetries = 3) => { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const response = await generateThumbnail(videoId, options);
// Poll for completion let status = 'pending'; while (status === 'pending' || status === 'processing') { await new Promise(resolve => setTimeout(resolve, 2000)); // Wait 2 seconds const statusResponse = await checkThumbnailStatus(response.jobId); status = statusResponse.status;
if (status === 'completed') { return statusResponse.url; } else if (status === 'failed') { throw new Error('Thumbnail generation failed'); } } } catch (error) { if (attempt === maxRetries) throw error; await new Promise(resolve => setTimeout(resolve, 1000 * attempt)); // Exponential backoff } }};Common Use Cases
Video Gallery Thumbnails
// Generate thumbnails for video galleryconst generateGalleryThumbnails = async (videos) => { const thumbnails = await Promise.all( videos.map(async (video) => { const response = await generateThumbnail(video.publicId, { width: 320, height: 180, timestampMs: 5000 // 5 seconds into video }); return { videoId: video.publicId, thumbnailUrl: response.url, jobId: response.jobId }; }) ); return thumbnails;};Social Media Previews
// Generate social media optimized thumbnailsconst generateSocialThumbnail = async (videoId) => { const response = await generateThumbnail(videoId, { width: 1200, height: 630, // Facebook optimal size timestampMs: 0 // Use opening frame }); return response.url;};Mobile App Thumbnails
// Generate mobile-optimized thumbnailsconst generateMobileThumbnail = async (videoId) => { const response = await generateThumbnail(videoId, { width: 640, height: 360, timestampMs: 10000 // 10 seconds into video }); return response.url;};Error Handling
Common Errors
| Status Code | Error | Description | Solution |
|---|---|---|---|
| 400 | Bad Request | Invalid dimensions or timestamp | Check width/height (1-4096) and timestamp (0 to video duration) |
| 401 | Unauthorized | Invalid API key | Verify API key is correct and active |
| 403 | Forbidden | Video doesn’t belong to organization | Ensure video belongs to your organization |
| 404 | Not Found | Video not found | Verify video public ID is correct |
| 422 | Unprocessable Entity | Timestamp exceeds video duration | Use timestamp within video length |
| 429 | Too Many Requests | Rate limit exceeded | Wait before making more requests |
Error Response Example
{ "title": "Bad Request", "status": 400, "detail": "Invalid thumbnail dimensions", "errors": [ { "message": "Width must be between 1 and 4096 pixels", "location": "body.width", "value": 5000 } ]}Rate Limits
| Operation | Limit | Window |
|---|---|---|
| Thumbnail generation | 50 requests | 1 hour |
| Status checks | 100 requests | 1 hour |
| Thumbnail retrieval | 1000 requests | 1 hour |
Tip
Thumbnail generation is processed asynchronously. Use the job ID to poll for completion status rather than making repeated generation requests.