Skip to main content

🌐 Webhooks

In this section, we detail the webhook notifications for the ZapCap API, covering the setup, structure, and processing of webhook messages.

Overview

Webhooks are a powerful way to get notified about the status of your video tasks. They allow you to receive real-time updates when specific events occur within the ZapCap API.

Notification Setup

When creating a video task, you can configure webhook notifications to receive updates on task status changes. This is specified in the notification object when creating a videoTask.

Example Notification Object

"notification": {
"type": "webhook",
"notificationsFor": ["transcript", "render", "renderProgress"],
"recipient": "https://example.com/api/webhook/zapcap"
}

Handling Webhook Messages

Notification Payload

The payload structure depends on the type of notification (NotificationFor) you have subscribed to. The possible values are transcript, render, and renderProgress.

Transcript Notification

If the notification is for a transcript task:

{
eventId: string; // Unique ID for deduplication
event: string; // The event type, [`failed`, `transcriptionCompleted`]
taskId: string; // The task ID
notificationFor: "transcript";
transcriptUrl: string | undefined; // presigned URL to access the transcript with a TTL of 60 minutes. Not set if transcription is not generated
}

Render Notification

If the notification is for a render task:

{
eventId: string; // Unique ID for deduplication
event: string; // The event type, [`failed`, `completed`]
taskId: string; // The task ID
notificationFor: "render";
transcriptUrl: string; // presigned URL to access the transcript with a TTL of 60 minutes. Not set if transcription is not generated
renderUrl: string | undefined; // presigned URL to access the rendered video with a TTL of 60 minutes. Not set if rendering fails
}

Render Progress Notification

If the notification is for render progress:

{
eventId: string; // Unique ID for deduplication
event: string; // The event type, [`rendering`]
taskId: string; // The task ID
notificationFor: "renderProgress";
progress: number; // A decimal value, between 0 and 1
}

Security

Signature Verification

To ensure the authenticity of the webhook message, a signature is included in the headers of the POST request. This signature helps verify that the message is indeed from ZapCap and has not been tampered with. You can verify this signature using your webhook secret found here.

What is the Signature?

The signature is a hashed representation of the payload, generated using the HMAC (Hash-based Message Authentication Code) algorithm with SHA-256. It combines your webhook secret and the payload to create a unique hash. This hash is then included in the headers of the POST request under the x-signature key.

Generating the Signature

Here's how the signature is generated:

const generatedSignature = crypto
.createHmac("sha256", body.webhookSecret) // Create a HMAC with SHA-256 using the webhook secret
.update(JSON.stringify(payload)) // Payload received in the webhook notification
.digest("hex"); // Output the HMAC as a hexadecimal string
return generatedSignature === receivedSignature; // Compare the received signature in x-signature header to the generated value

Complete Implementation Example

Here's a complete Express.js webhook handler with signature verification:

import express from "express";
import crypto from "crypto";

const app = express();

// Get this from https://platform.zapcap.ai/dashboard/api-key
const WEBHOOK_SECRET = "your_webhook_secret";

// Store processed event IDs to prevent duplicate processing
const processedEvents = new Set();

app.post("/webhook/zapcap", express.json(), (req, res) => {
const payload = req.body;
const receivedSignature = req.headers["x-signature"];

// 1. Verify signature
const generatedSignature = crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(JSON.stringify(payload))
.digest("hex");

if (generatedSignature !== receivedSignature) {
console.error("Invalid webhook signature");
return res.status(401).json({ error: "Invalid signature" });
}

// 2. Check for duplicate events (idempotency)
if (processedEvents.has(payload.eventId)) {
return res.status(200).json({ message: "Already processed" });
}

// 3. Acknowledge immediately, process async
res.status(200).json({ received: true });

// 4. Process the webhook asynchronously
processWebhook(payload);
});

async function processWebhook(payload) {
try {
processedEvents.add(payload.eventId);

switch (payload.notificationFor) {
case "transcript":
if (payload.event === "transcriptionCompleted") {
console.log("Transcript ready:", payload.transcriptUrl);
// Download and process transcript...
} else if (payload.event === "failed") {
console.error("Transcription failed for task:", payload.taskId);
}
break;

case "render":
if (payload.event === "completed") {
console.log("Video ready:", payload.renderUrl);
// Download and store the video...
} else if (payload.event === "failed") {
console.error("Render failed for task:", payload.taskId);
}
break;

case "renderProgress":
console.log(`Render progress: ${Math.round(payload.progress * 100)}%`);
break;
}
} catch (error) {
console.error("Error processing webhook:", error);
}
}

app.listen(3000, () => console.log("Webhook server running on port 3000"));

Successful Processing

Your endpoint should return a 200 status code within 300 ms. This tight timeout means you should:

  1. Acknowledge immediately - Return 200 as soon as you receive and validate the webhook
  2. Process asynchronously - Queue the actual work (downloading files, updating databases) for background processing
  3. Don't block on I/O - Never make external API calls or database writes before responding
Best Practice

The example above demonstrates this pattern: it responds with res.status(200) immediately after validation, then calls processWebhook() asynchronously. This ensures you never miss the 300ms window.

Retries

If the ZapCap API doesn't receive a 200 status code response in a timely manner, it will attempt to resend the message to the webhook endpoint up to 5 times.

Conclusion

Webhooks provide a flexible way to get real-time updates on your video tasks. Ensure your webhook endpoint is secure, processes messages correctly, and returns the appropriate status codes to maintain efficient communication with the ZapCap API.