Webhooks are currently available to Scale customers only, if you’re interested contact us.

Handle duplicate events

Webhook endpoints might occasionally receive the same event more than once. You can guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you’ve processed, and then not processing already-logged events. Each event payload includes an event URN—a unique identifier for the event—which can be used as an idempotency key.

Only listen to event types your integration requires

Configure your webhook endpoints to receive only the types of events required by your integration. Listening for extra events (or all events) puts undue strain on your server and we don’t recommend it.

You can change the events that a webhook endpoint receives by updating the webhook object using the updateWebhook mutation.

Handle events asynchrounously

The volume of events that get generated can be spike-y. A data enrichment may result in millions of objects being updated in a very short period of time. Configure your handler to process incoming events with an asynchronous queue. You might encounter scalability issues if you choose to process events synchronously. Any large spike in webhook deliveries (for example, during a large data enrichment) might overwhelm your endpoint hosts.

Asynchronous queues allow you to process the concurrent events at a rate your system can support. For example, your webhook endpoint could simply verify a payload and then push the event directly to a queue (like AWS SQS) where you can then process the events with better concurrency control.

Receive events with an HTTPS server

You must use an HTTPS URL for your webhook endpoint. Brandfetch validates that the connection to your server is secure before sending your webhook data. For this to work, your server must be correctly configured to support HTTPS with a valid server certificate.

Verify events are sent from Brandfetch

Verify webhook signatures to confirm that received events are sent from Brandfetch. Brandfetch signs webhook payload sent to your endpoints by including a signature in each event’s Webhook-Signature header. This allows you to verify that the events were sent by Brandfetch, not by a third party.

Preventing replay attacks

A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. To mitigate such attacks, Brandfetch includes a timestamp in the Webhook-Signature header. Because this timestamp is part of the signed payload, it’s also verified by the signature, so an attacker can’t change the timestamp without invalidating the signature. If the signature is valid but the timestamp is too old, you can have your application reject the payload.

We recommend a tolerance of no greater than 5 minutes between the timestamp and the current time. Use Network Time Protocol (NTP) to make sure that your server’s clock is accurate and is in-sync with the time on Brandfetch’s servers.

Brandfetch generates the timestamp and signature each time we send an event to your endpoint. If Brandfetch retries an event (for example, your endpoint previously replied with a non-2xx status code), then we generate a new signature and timestamp for the new delivery attempt.

Example code for handling signature and timing verification

JavaScript
import crypto from "node:crypto";

const TIMESTAMP_TOLERANCE_IN_MILISECONDS = 2 * 60 * 1000; // 2 minutes

function hasVerifiedPayload({ sharedWebhookSecret, headers, rawRequestBody }) {
  const webhookId = headers["webhook-id"];
  const signature = headers["webhook-signature"].split(",")[1];
  const timestamp = Number(headers["webhook-timestamp"]);
  const signatureAlgorithm = headers["webhook-signature-algorithm"];
  const now = Date.now();

  const signatureIsOk =
    crypto
      .createHmac(signatureAlgorithm, sharedWebhookSecret)
      .update(`${webhookId}.${timestamp}.${rawRequestBody}`)
      .digest("hex") === signature;

  const timingIsOk =
    timestamp < now && timestamp > now - TIMESTAMP_TOLERANCE_IN_MILISECONDS;

  return signatureIsOk && timingIsOk;
}

Quickly return a 2xx response

Your endpoint must quickly return a successful status code (2xx) prior to any complex logic that could cause a timeout. For example, you must return a 200 response before updating any records in your database or making additional API requests.