Skip to main content

Getting started with Webhooks

How to set up webhooks in the Settings page and send your application events from Harmonic

Written by Harmonic Team

Overview

Webhooks let Harmonic push list events straight to an endpoint you own, so you don't have to poll the API to notice changes. When a company (or person, or investor) is added to or removed from a subscribed list, Harmonic POSTs a signed JSON event to your URL within seconds.

Today webhooks support two event types: a list entry being created and a list entry being deleted. Attribute changes and other event types are on the roadmap.

Set up a webhook

You can create and manage webhooks from the Harmonic console. API-only setup is also supported — see the Webhooks API Reference.

1. Go to Settings → Webhooks

2. Click + Add new.

3. Fill in the webhook details:

  • Name — a label for your reference, e.g. Production CRM Sync.

  • Endpoint URL — the HTTPS URL Harmonic will POST events to.

  • Lists to receive events from — pick one or more lists. The webhook will fire on entries added to or removed from any of them. Optionally, you can subscribe to specific events only. Note: the list must be Shared with your team to be accessible via API or via Webhooks.

4. Click Save.

5. Copy the signing secret. It's shown only once, right after you save. Store it somewhere secure — your application will use it to verify that incoming requests actually came from Harmonic. If you lose it, you can rotate the secret from the webhook's settings.

Verify webhook deliveries

Every request Harmonic sends includes a signature header so you can confirm it's authentic and hasn't been tampered with. Before you trust the body of a webhook, verify the signature using the signing secret you copied above.

The signature is v1= followed by the lowercase hex HMAC-SHA256 of the string <X-Harmonic-Timestamp>.<raw request body>, keyed by your signing secret. Compute the same digest over the raw received bytes (before any JSON re-serialization) and compare in constant time.

Node.js example:

const crypto = require('crypto');

// rawBody MUST be the raw request bytes (e.g. express.raw()),
// not a re-stringified object.
function verifyHarmonicWebhook(rawBody, headers, signingSecret, toleranceSec = 300) {
const timestamp = headers['x-harmonic-timestamp'];
const signature = headers['x-harmonic-signature']; // "v1=<hex>"

const skew = Math.abs(Math.floor(Date.now() / 1000) - Number(timestamp));
if (!timestamp || skew > toleranceSec) {
throw new Error('timestamp outside tolerance');
}

const expected = 'v1=' + crypto
.createHmac('sha256', signingSecret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');

const a = Buffer.from(expected);
const b = Buffer.from(signature ?? '');
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
throw new Error('signature mismatch');
}
return JSON.parse(rawBody);
}

Python example:

import hashlib, hmac, time

def verify_harmonic_webhook(raw_body: bytes, headers, signing_secret: str, tolerance_sec: int = 300):
timestamp = headers["X-Harmonic-Timestamp"]
signature = headers["X-Harmonic-Signature"] # "v1=<hex>"

if abs(int(time.time()) - int(timestamp)) > tolerance_sec:
raise ValueError("timestamp outside tolerance")

signed = f"{timestamp}.".encode() + raw_body
digest = hmac.new(signing_secret.encode(), signed, hashlib.sha256).hexdigest()
expected = f"v1={digest}"

if not hmac.compare_digest(expected, signature):
raise ValueError("signature mismatch")
return raw_body

Also reject deliveries whose X-Harmonic-Timestamp is more than 5 minutes off from your clock, as a replay guard.

Test your webhook

Each webhook has a Test button in its settings. Clicking it sends a synthetic webhook.test event to your endpoint right away and shows you exactly what your endpoint returned — the HTTP status, response time, and any error detail.

Use it to confirm two things before you start routing real traffic:

  1. Harmonic can reach your endpoint and it responds with a 2xx.

  2. Your signature verification works end-to-end.

Note: the test event is a synthetic webhook.test payload, not a real list event. Use it to validate connectivity and signatures — don't use it to validate list-event parsing.

Retries & auto-disable

Harmonic treats any non-2xx response, a timeout, or a refused connection as a failed delivery. Each delivery attempt times out at 5 seconds, so respond quickly and do any heavy work asynchronously.

Retries. Failed deliveries are retried up to 8 times per event with exponential backoff.

Auto-disable. After 20 consecutive undeliverable events, Harmonic sets the webhook's status to AUTO_DISABLED and emails the notification address on the webhook. A single successful delivery resets the streak. Once your endpoint is healthy again, re-enable the webhook from its settings — this clears the auto-disabled status and resets the failure counters.

Replay failures. You can replay failed deliveries (or dismiss them without resending) from the webhook's failures view, or via the API.

De-duplicate on event ID. Every delivery carries a stable top-level id (also sent as the X-Harmonic-Event-Id header). The same ID is reused across redeliveries of the same event, so treat a repeat ID as already-processed.

Limits & what's supported today

Supported events. Webhooks fire on list entries being created or deleted. Attribute changes, list changes, and other event types aren't delivered as webhooks yet — if that would unblock a workflow for you, let us know.

One webhook, many lists. A single webhook endpoint can subscribe to many lists. Each list can also be subscribed by multiple webhooks. Currently we support subscribing up to 1000 lists to a single webhook endpoint.

Endpoint cap per workspace. Your workspace has a maximum number of webhook endpoints. We support up to 50 webhook endpoints per workspace.

HTTPS only. Endpoint URLs must be HTTPS. Internal, private, or non-routable addresses are rejected.

Delivery timeout. 5 seconds per attempt. Respond 2xx fast; do longer work in a background job.

Where to next

Did this answer your question?