Webhooks
JobsPipe webhooks push job events to your endpoint with signed payloads - job.closed and job.created, HMAC-SHA256 verification, retries.
JobsPipe webhooks POST job events to your endpoint as they happen, so you don't poll. Webhooks are available on paid plans and are configured from the dashboard, where signing secrets are issued and rotated.
Events
| Event | Fires when |
|---|---|
job.closed | A tracked job posting transitions from open to closed. |
job.created | A new posting matches one of your saved subscriptions. |
The delivery body is JSON:
{
"event": "job.closed",
"id": "evt_01j8...",
"timestamp": 1789999999,
"data": { "id": "...", "job_title": "...", "company": "..." }
}data carries the job fields in the same shape as the
job schema.
Verifying signatures
Every delivery carries two headers:
| Header | Contents |
|---|---|
X-JobsPipe-Signature | Hex HMAC-SHA256 of `${timestamp}.${rawBody}` with your secret |
X-JobsPipe-Timestamp | Unix seconds when the delivery was signed |
Recompute the HMAC over the timestamp, a dot, and the raw request body, and compare in constant time. Reject deliveries whose timestamp is older than five minutes to guard against replay.
import { createHmac, timingSafeEqual } from "node:crypto";
function verify(rawBody: string, signature: string, timestamp: string, secret: string) {
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = createHmac("sha256", secret)
.update(`${timestamp}.${rawBody}`)
.digest("hex");
return (
expected.length === signature.length &&
timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
);
}Delivery and retries
Respond with any 2xx within 5 seconds to acknowledge. Anything else - or a
timeout - triggers retries with exponential backoff.
The full webhook contract also ships in the machine-readable
OpenAPI specification under webhooks.