Home/Docs/Webhooks

Developer

Webhooks

Updated 2026-05-18

Crawlmind webhooks deliver JSON POSTs to a URL of your choosing whenever something interesting happens — a crawl completes, an alert fires, a subscription changes. Each delivery is signed with HMAC-SHA256 so you can verify it came from us. Available on Pro+.

Creating a webhook

From /orgs/<id>/webhooksNew webhook. Provide:

  • URL — your endpoint (must be HTTPS, public, no auth header — we verify via signature instead)
  • Events — pick from the event catalogue below
  • Secret — we auto-generate one; copy it now (we hash + discard, can't show again)

Delivery is at-least-once. Your handler must be idempotent — keying on the delivery.id field is the canonical pattern.

Event catalogue

EventFires when
crawl.succeededA CrawlJob ends in SUCCEEDED / PARTIAL
crawl.failedA CrawlJob ends in FAILED
alert.triggeredAn AlertRule fires
subscription.createdNew paid subscription
subscription.updatedPlan or status changed
subscription.canceledSubscription canceled
report.readyA PDF report finished generating
citation.run.completedA citation-tracking run finished

Payload shape

Every payload is the same envelope:

{
  "id": "dlv_2x9Ye3...",
  "event": "crawl.succeeded",
  "occurredAt": "2026-05-18T08:42:00Z",
  "organizationId": "org_xxx",
  "data": {
    "crawlJobId": "cj_xxx",
    "websiteId": "wbs_xxx",
    "overallScore": 87,
    "issueCount": 14
  }
}

data shape varies by event type.

Verifying the signature

Every delivery includes two headers:

X-Crawlmind-Signature: t=1779087847,v1=abc123...
X-Crawlmind-Event: crawl.succeeded

Verify with HMAC-SHA256(secret, {t}.{rawBody}):

import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const [, t, , v] = header.match(/t=(\d+),v1=([a-f0-9]+)/) || [];
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(v, "hex"),
  );
}

Reject any delivery older than 5 minutes (replay protection).

Retries + dead-letter

A delivery is retried with exponential backoff on any non-2xx response: 1m, 5m, 30m, 2h, 12h. After 5 failures the delivery is moved to a dead-letter queue and an alert.triggered event fires for the operator. View dead-lettered deliveries from /orgs/<id>/webhooks/deliveries.

Related docs

Ready to try it?

Free tier: 5 crawls / month, no credit card.