Webhooks
What a webhook is
Benchmark sends one webhook event as a JSON POST to your HTTPS URL when a
collection finishes.
The event type is collection.completed or collection.failed.
Set it up
Only a workspace admin can manage webhooks.
- Open Webhooks in the dashboard settings.
- Enter your HTTPS URL in Webhook URL. The URL must use the default HTTPS port and a public host name.
- Select Save and generate secret.
- Copy the Signing secret. It is shown one time.
After setup, the button says Rotate secret. Rotating saves the URL and a new secret at once. New events use the new values. Events that are already waiting, and their retries, keep the old URL and secret.
What Benchmark sends
Every event has these fields:
eventId: the event ID.collectionId: the collection ID.type: the event type.entityType:profile,post, orlink.dataLevel:basicorenriched.changed_fields: an optional list of fields that changed.data: the result for a completed event,nullwhen the data is not available, or an empty object for a failed event.coverage: present whendataisnull. It says why no public result was available.privatemeans the source indicates that the content is not public. Benchmark does not retrieve it.not_foundmeans the content was not found.
This failed event uses values from the API description:
{ "collectionId": "20000000-0000-4000-8000-000000000003", "dataLevel": "enriched", "data": {}, "entityType": "post", "eventId": "70000000-0000-4000-8000-000000000008", "type": "collection.failed"}Webhook events contain only the structured fields shown in the schema. They do not include source media or transcript content.
Headers
Each request has these headers:
Benchmark-Idempotency-Key: the event ID.Benchmark-Timestamp: the number of seconds since January 1, 1970.Benchmark-Signature: the request signature.
Check the signature
The signature starts with v1=. The rest is the hex HMAC-SHA256 of
TIMESTAMP.BODY. Benchmark uses your signing secret as the key. BODY is the
exact raw request body.
Check each request in this order:
- Read the raw body before you parse the JSON.
- Join the timestamp, a period, and the raw body as
TIMESTAMP.BODY. - Compute the HMAC-SHA256 with your signing secret.
- Compare the two values in constant time.
- Reject old timestamps. You can choose five minutes as your own limit. Benchmark does not set a time limit for you.
- Use
Benchmark-Idempotency-Keyto ignore repeats.
This Node.js example checks a raw Buffer body:
import { createHmac, timingSafeEqual } from "node:crypto";
function hasValidSignature({ rawBody, secret, signature, timestamp }) { const match = /^v1=([0-9a-f]{64})$/.exec(signature); if (!match) return false;
const expected = createHmac("sha256", secret) .update(timestamp) .update(".") .update(rawBody) .digest(); const received = Buffer.from(match[1], "hex");
return timingSafeEqual(expected, received);}
const rawBody = Buffer.from('{"type":"collection.failed"}');const secret = "YOUR_WEBHOOK_SECRET";const timestamp = "1787563200";const signature = "YOUR_BENCHMARK_SIGNATURE";
console.log(hasValidSignature({ rawBody, secret, signature, timestamp }));Retries
Benchmark retries when the request times out, the network fails, or your server
returns 408, 429, or any 5xx status. It makes up to eight tries in total.
The wait gets longer after each failed try.
Benchmark follows up to three redirects. These stop the retries: any other 3xx
or 4xx response, too many redirects, or a URL that Benchmark cannot send to.
Return any 2xx response as soon as you can.
A webhook can arrive more than once. Use the idempotency key to ignore repeats.
A late or failed webhook does not change the collection. You can always check it with
GET /v1/collections/COLLECTION_ID.