Webhooks

Webhooks offer an efficient way to receive status updates on your generation jobs. Instead of polling for the status updates, webhooks notify you when a job completes or fails.

Integrating webhooks

To utilize webhooks:

  1. Specify a webhookUrl parameter when calling an API endpoints that support it.
  2. Ensure your webhook endpoint can receive and handle HTTP POST requests and can consume the Webhook Payload for status updates.

For security purposes, your webhook URL must be configured to accept and process HTTPS POST requests.

By leveraging webhooks, you can streamline your workflow with non-blocking calls, allowing you to focus on other tasks while receiving job completion notifications.

Verify webhook signatures

To ensure webhook requests are coming from Sync, we sign each webhook request with a signature. The signature is included in the Sync-Signature header.

To verify signatures, use your signing secret.

The signature is made out of 2 components:

  • Timestamp (at the time of sending the event)
  • Signature hash (timestamp and the JSON payload)
1const express = require("express");
2const { createHmac, timingSafeEqual } = require("crypto");
3
4const app = express();
5
6const WEBHOOK_SECRET = "whsec_";
7
8app.use(express.json());
9
10const verifySignature = (payload, signature, secret) => {
11 try {
12 if (!signature) {
13 return false;
14 }
15 const [, timestamp, receivedSignature] =
16 signature.match(/t=(\d+),v1=(.+)/) ?? [];
17 if (!timestamp || !receivedSignature) {
18 return false;
19 }
20
21 const expectedSignature = createHmac("sha256", secret)
22 .update(`${timestamp}.${JSON.stringify(payload)}`)
23 .digest("hex");
24
25 // Timing-safe comparison to prevent timing attacks
26 return timingSafeEqual(
27 Buffer.from(receivedSignature),
28 Buffer.from(expectedSignature)
29 );
30 } catch (error) {
31 return false;
32 }
33};
34
35app.post("/webhook", (req, res) => {
36 const signature = req.headers["sync-signature"];
37
38 if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
39 return res.status(400).json({
40 message: "Invalid signature",
41 });
42 }
43
44 return res.status(200).json({
45 message: "Webhook signature verified",
46 });
47});
48
49app.listen(8080, () => {});