Webhooks

8 min read
Last updated: January 15, 2024

Webhooks allow your application to receive real-time notifications when events occur in VideoPilot. Instead of polling the API for updates, webhooks push event data directly to your server.

How Webhooks Work
VideoPilot sends HTTP POST requests to your configured endpoints when events occur
1

Event Occurs

Video generation completes, render finishes, etc.

2

Webhook Sent

VideoPilot sends event data to your endpoint

3

You Respond

Your app processes the event and responds with 200 OK

Setting Up Webhooks
Configure webhook endpoints in your account settings
1Go to your Account Settings in the VideoPilot dashboard
2Navigate to the "Webhooks" section
3Add a new webhook endpoint URL
4Select which events you want to receive
5Save your configuration
Configure Webhooks
Available Events
Webhook events you can subscribe to

Video Events

video.script_ready

Triggered when script generation is complete

{
  "event": "video.script_ready",
  "data": {
    "video_id": "video_123abc",
    "title": "Space Discovery",
    "script": "In a galaxy far, far away, a brave astronaut begins their journey through the cosmos...",
    "status": "script_ready",
    "scene_count": 8
  },
  "timestamp": "2024-01-15T10:30:00.000Z"
}
video.media_ready

Triggered when all scene media generation is complete

{
  "event": "video.media_ready", 
  "data": {
    "video_id": "video_123abc",
    "title": "Space Discovery",
    "status": "media_ready",
    "scene_count": 8,
    "total_duration": 87.5,
    "scenes_with_images": 8,
    "scenes_with_audio": 8
  },
  "timestamp": "2024-01-15T10:35:00.000Z"
}
video.generation_failed

Triggered when video generation encounters an error

{
  "event": "video.generation_failed",
  "data": {
    "video_id": "video_123abc",
    "title": "Space Discovery", 
    "status": "failed",
    "error": "Image generation failed for scene 3",
    "failed_step": "image_generation"
  },
  "timestamp": "2024-01-15T10:25:00.000Z"
}

Render Events

render.started

Triggered when video rendering begins

{
  "event": "render.started",
  "data": {
    "render_job_id": "render_789xyz",
    "video_id": "video_123abc",
    "status": "processing",
    "quality": "high",
    "estimated_duration": 180
  },
  "timestamp": "2024-01-15T10:40:00.000Z"
}
render.completed

Triggered when video rendering is finished

{
  "event": "render.completed",
  "data": {
    "render_job_id": "render_789xyz",
    "video_id": "video_123abc",
    "status": "completed",
    "output_url": "https://cdn.videopilot.app/videos/video_123abc_high.mp4",
    "duration": 87.5,
    "file_size": 25690112,
    "quality": "high"
  },
  "timestamp": "2024-01-15T10:43:30.000Z"
}
render.failed

Triggered when video rendering fails

{
  "event": "render.failed",
  "data": {
    "render_job_id": "render_789xyz",
    "video_id": "video_123abc",
    "status": "failed",
    "error": "Rendering timeout after 300 seconds",
    "quality": "high"
  },
  "timestamp": "2024-01-15T10:45:00.000Z"
}
Webhook Security
Verify webhook authenticity using signatures

Each webhook request includes a signature in the X-VideoPilot-Signature header. Verify this signature to ensure the request comes from VideoPilot:

Node.js/Express Example

"text-blue-400 font-semibold">const crypto = require('crypto');
"text-blue-400 font-semibold">const express = require('express');

"text-blue-400 font-semibold">function verifyWebhook(payload, signature, secret) {
  "text-blue-400 font-semibold">const hmac = crypto.createHmac('sha256', secret);
  hmac.update(payload, 'utf8');
  "text-blue-400 font-semibold">const expectedSignature = 'sha256=' + hmac.digest('hex');
  
  "text-blue-400 font-semibold">return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post('/webhook', express.raw({type: 'application/json'}), (req, res) => {
  "text-blue-400 font-semibold">const signature = req.get('X-VideoPilot-Signature');
  "text-blue-400 font-semibold">const payload = req.body.toString();
  
  "text-blue-400 font-semibold">const isValid = verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET);
  
  "text-blue-400 font-semibold">if (!isValid) {
    "text-blue-400 font-semibold">return res.status(401).send('Invalid signature');
  }
  
  "text-blue-400 font-semibold">const event = JSON.parse(payload);
  console.log('Received event:', event.event);
  
  // Process the webhook event
  switch (event.event) {
    case 'video.media_ready':
      // Queue "text-blue-400 font-semibold">for rendering
      "text-blue-400 font-semibold">await queueVideoForRendering(event.data.video_id);
      break;
      
    case 'render.completed':
      // Notify user or update database
      "text-blue-400 font-semibold">await notifyUserVideoReady(event.data);
      break;
  }
  
  res.status(200).send('OK');
});

Python/Flask Example

import hmac
import hashlib
import os
from flask import Flask, request

app = Flask(__name__)

def verify_webhook(payload, signature, secret):
    expected_signature = 'sha256=' + hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    ).hexdigest()
    
    return hmac.compare_digest(signature, expected_signature)

@app.route('/webhook', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-VideoPilot-Signature')
    payload = request.get_data()
    
    if not verify_webhook(payload, signature, os.getenv('WEBHOOK_SECRET')):
        return 'Invalid signature', 401
    
    event = request.get_json()
    print(f"Received event: {event['event']}")
    
    # Process the webhook event
    if event['event'] == 'video.media_ready':
        # Queue for rendering
        queue_video_for_rendering(event['data']['video_id'])
    elif event['event'] == 'render.completed':
        # Notify user or update database
        notify_user_video_ready(event['data'])
    
    return 'OK', 200
Best Practices
Tips for reliable webhook handling

Respond quickly

Return a 200 status code within 30 seconds. Process heavy work asynchronously.

Handle idempotency

Use the event ID to prevent processing duplicate events.

Verify signatures

Always verify webhook signatures to ensure authenticity.

Handle failures gracefully

VideoPilot will retry failed webhooks up to 3 times with exponential backoff.

Log events

Keep logs of webhook events for debugging and monitoring.

Testing Webhooks
Tools and techniques for webhook development

Local Development

Use ngrok or similar tools to expose your local server for webhook testing:

# Install ngrok
"text-blue-400 font-semibold">npm install -g ngrok

# Expose your local server
ngrok http 3000

# Use the HTTPS URL as your webhook endpoint
# https://abc123.ngrok.io/webhook

Webhook Testing Tools

  • webhook.site - Test webhook endpoints without code
  • RequestBin - Inspect webhook payloads
  • ngrok - Local development tunneling
  • Postman - Mock webhook requests