Documentation Index
Fetch the complete documentation index at: https://docs.videobgremover.com/llms.txt
Use this file to discover all available pages before exploring further.
Why Use Webhooks?
Instead of repeatedly calling the API to check if your video is done (polling), webhooks notify you instantly when processing completes.
Polling (Inefficient)
// ❌ Wastes resources, adds latency
while (true) {
const status = await client.status(jobId)
if (status.status === 'completed') break
await sleep(5000) // Check every 5 seconds
}
Webhooks (Efficient)
// ✅ Instant notification, no wasted API calls
await client.startJob(jobId, {
webhook_url: 'https://your-app.com/webhooks/videobgremover',
background: { type: 'transparent' }
})
// Server notifies you when done
Benefits:
- Real-time: Get notified instantly when processing completes
- Efficient: No repeated API calls or bandwidth waste
- Scalable: Process multiple videos without constant polling
When to use webhooks vs polling:
- ✅ Use webhooks for production apps, automation, background processing
- ⚠️ Use polling for quick scripts, testing, or if you can’t receive HTTP requests
How VideoBGRemover Webhooks Work
When you start a job with a webhook_url, our system:
- Validates your webhook URL (HTTPS required in production)
- Stores the URL with your job
- Triggers 3 events during processing:
job.started - Processing begins
job.completed - Video ready (includes output URLs)
job.failed - Processing failed (includes error message)
- Sends POST request to your URL with JSON payload
- Retries up to 3 times (10 seconds apart) if delivery fails
- Waits for BOTH background removal AND export to complete before final webhook
The system waits for your complete video (with composition/export) before sending the job.completed webhook. This prevents premature notifications.
Quick Setup
Your webhook endpoint must:
- Accept
POST requests with Content-Type: application/json
- Return a
2xx status code quickly (< 5 seconds)
- Use HTTPS (production only - HTTP allowed for testing)
Using Webhooks via cURL
Add webhook_url to your job start request:
# 1. Create job
JOB=$(curl -s -X POST https://api.videobgremover.com/v1/jobs \
-H "X-Api-Key: $API_KEY" \
-F "file=@video.mp4")
JOB_ID=$(echo $JOB | jq -r '.id')
# 2. Start job with webhook
curl -X POST https://api.videobgremover.com/v1/jobs/$JOB_ID/start \
-H "X-Api-Key: $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"webhook_url": "https://your-app.com/webhooks",
"background": {
"type": "transparent",
"transparent_format": "webm_vp9"
}
}'
Response:
{
"message": "Job started",
"status": "processing",
"webhook_url": "https://your-app.com/webhooks"
}
Using Webhooks via API Client (Low-Level)
Use the VideoBGRemoverClient class for direct API control:
import { VideoBGRemoverClient } from 'videobgremover'
const client = new VideoBGRemoverClient(process.env.API_KEY!)
// Create job from file
const job = await client.createJobFile({
file: './video.mp4'
})
// Start with webhook
await client.startJob(job.id, {
webhook_url: 'https://your-app.com/webhooks',
background: {
type: 'transparent',
transparent_format: 'webm_vp9'
}
})
console.log('Job started, webhook will notify when complete')
Using Webhooks via SDK (High-Level)
Use the Video class for simpler workflows:
import { VideoBGRemoverClient, Video, RemoveBGOptions, Prefer } from 'videobgremover'
const client = new VideoBGRemoverClient(process.env.API_KEY!)
// Load video
const video = await Video.open('./video.mp4')
// Remove background with webhook
const foreground = await video.removeBackground({
client,
webhookUrl: 'https://your-app.com/webhooks',
options: new RemoveBGOptions(Prefer.WEBM_VP9)
})
console.log('Processing started, webhook will notify when complete')
Webhook support for the high-level video.removeBackground() SDK method is coming soon. For now, use the low-level client.startJob() API shown above for webhook functionality.
Webhook Events & Payloads
Your webhook endpoint will receive POST requests with these payloads:
job.started
Fires when processing begins.
{
"event": "job.started",
"timestamp": "2025-11-01T12:30:00.123Z",
"job": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "processing",
"filename": "my-video.mp4",
"created_at": "2025-11-01T12:30:00.000Z"
}
}
job.completed
Fires when BOTH background removal AND export complete.
{
"event": "job.completed",
"timestamp": "2025-11-01T12:35:00.456Z",
"job": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"export_id": "exp_webm_vp9_123",
"status": "completed",
"filename": "my-video.mp4",
"length_seconds": 30.5,
"output_format": "webm",
"background": {
"type": "transparent",
"transparent_format": "webm_vp9"
}
}
}
To download the processed video, call the status endpoint: GET /v1/jobs/{id}/status which returns the processed_video_url field with the download URL.
job.failed
Fires when processing or export fails.
{
"event": "job.failed",
"timestamp": "2025-11-01T12:32:00.789Z",
"job": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"filename": "my-video.mp4",
"message": "Video file too large: 1250.5MB exceeds limit of 1000MB"
}
}
Webhooks include these headers:
POST /your/webhook/endpoint
Content-Type: application/json
User-Agent: VideoBGRemover-Webhooks/1.0
X-VideoBGRemover-Event: job.completed
X-VideoBGRemover-Job-ID: 550e8400-e29b-41d4-a716-446655440000
X-VideoBGRemover-Timestamp: 2025-11-01T12:35:00.456Z
X-VideoBGRemover-Attempt: 1
Checking Delivery History
View webhook delivery attempts and results:
API Endpoint
curl "https://api.videobgremover.com/v1/webhooks/deliveries?video_id=$JOB_ID" \
-H "X-Api-Key: $API_KEY"
SDK Methods
const deliveries = await client.webhookDeliveries(jobId)
console.log(`Total deliveries: ${deliveries.total_deliveries}`)
deliveries.deliveries.forEach(d => {
console.log(`${d.event_type}: ${d.delivery_status} (attempt ${d.attempt_number})`)
if (d.error_message) {
console.log(` Error: ${d.error_message}`)
}
})
Response:
{
"video_id": "550e8400-e29b-41d4-a716-446655440000",
"total_deliveries": 2,
"deliveries": [
{
"event_type": "job.started",
"webhook_url": "https://your-app.com/webhooks",
"attempt_number": 1,
"delivery_status": "delivered",
"http_status_code": 200,
"error_message": null,
"scheduled_at": "2025-11-01T12:30:00.000Z",
"delivered_at": "2025-11-01T12:30:00.234Z"
},
{
"event_type": "job.completed",
"webhook_url": "https://your-app.com/webhooks",
"attempt_number": 1,
"delivery_status": "delivered",
"http_status_code": 200,
"error_message": null,
"scheduled_at": "2025-11-01T12:35:00.000Z",
"delivered_at": "2025-11-01T12:35:00.567Z"
}
]
}
Best Practices
Process webhooks asynchronously to avoid timeouts:
// ✅ Good: Return immediately, process async
app.post('/webhooks', async (req, res) => {
res.status(200).send('OK') // Return first
// Process async
await processWebhook(req.body).catch(console.error)
})
// ❌ Bad: Slow processing blocks response
app.post('/webhooks', async (req, res) => {
await downloadVideo(req.body.job.processed_video_url) // Slow!
res.status(200).send('OK') // Timeout risk
})
Handle Retries
Use attempt_number to detect retries:
app.post('/webhooks', (req, res) => {
const { job } = req.body
const attempt = parseInt(req.headers['x-videobgremover-attempt'])
if (attempt > 1) {
console.log(`Retry attempt ${attempt} for job ${job.id}`)
}
// Process idempotently
res.status(200).send('OK')
})
Validate Events
Check event type before processing:
const VALID_EVENTS = ['job.started', 'job.completed', 'job.failed']
if (!VALID_EVENTS.includes(req.body.event)) {
return res.status(400).send('Invalid event')
}
Use HTTPS
Production webhooks require HTTPS for security.
Common Issues
Webhook Not Received
- Check delivery history using the API or SDK
- Verify HTTPS (required in production)
- Check firewall - ensure your server is publicly accessible
- Test with webhook.site to verify our system is sending correctly
Duplicate Webhooks
This is expected during retries. Implement idempotency:
const processedJobs = new Set()
app.post('/webhooks', (req, res) => {
const jobId = req.body.job.id
if (processedJobs.has(jobId)) {
return res.status(200).send('Already processed')
}
processedJobs.add(jobId)
// Process webhook...
})
Timeout Errors
- Optimize your webhook endpoint to respond in < 5 seconds
- Return 200 immediately, process asynchronously
- Check delivery history to see timeout errors
Security Note: Webhooks do not currently include HMAC signatures. Use unpredictable webhook URLs (include random tokens) and validate job IDs via the API if security is critical.
Next Steps