The Detective

Send it elsewhere

Coming soon

Pipe every analysis into whatever you already run.

Signed outbound events on every delivery, every watchlist alert, every playbook update. You point us at an HTTPS endpoint. We POST JSON. You build the rest.

Events we emit

Three event types at launch.

analysis.delivered

Fires when a new ranked analysis lands in your dashboard. The payload carries the report id, the top niche verdict, the ranked list size, and the source confidence summary so you can route by tier of evidence.

niche.alert

Fires when a niche on your watchlist shows a positive delta in a fresh report. Rising demand signal, new competitor entry, regulatory shift on the kill condition you logged. One event per niche per delivery.

playbook.updated

Fires when an on demand AI playbook finishes generating, or when a saved playbook is rederived against a fresh analysis. Carries the playbook id and a diff summary so you only sync what changed.

More event types follow once the first three are stable in production. We will version the schema and ship a deprecation window before any breaking change.

Payload shape

A real analysis.delivered body.

Every event is JSON. Envelope fields are stable across event types. The data object varies by event. Timestamps are ISO 8601 UTC. Ids are ULIDs you can sort lexicographically.

jsonexample
{
  "id": "evt_01HM4Q6V8R2X9YJZP3T0K1B7AS",
  "type": "analysis.delivered",
  "created_at": "2026-05-22T14:00:00.000Z",
  "tier": "operator",
  "data": {
    "analysis_id": "rpt_01HM4Q6V8R2X9YJZP3T0K1B7AS",
    "delivered_at": "2026-05-22T14:00:00.000Z",
    "top_niche": {
      "slug": "sworn-translators-spain-maec",
      "title": "Sworn translators registered with Spain MAEC",
      "verdict": "GO_WITH_CAVEATS",
      "score": 78,
      "kill_condition": "MAEC fee schedule restructures in 2026 Q4"
    },
    "ranked_count": 20,
    "source_confidence": {
      "primary": 14,
      "industry": 9,
      "media": 4,
      "low": 1
    },
    "dashboard_url": "https://thedetective.io/dashboard/analyses/rpt_01HM4Q6V8R2X9YJZP3T0K1B7AS"
  }
}

Request headers

httpexample
POST /webhooks/the-detective HTTP/1.1
Host: your-server.example.com
Content-Type: application/json
User-Agent: TheDetective-Webhooks/1.0
X-Detective-Event: analysis.delivered
X-Detective-Delivery: evt_01HM4Q6V8R2X9YJZP3T0K1B7AS
X-Detective-Timestamp: 1747922400
X-Detective-Signature: t=1747922400,v1=5b9f3c9a8d2e1f7c4b6a2d8e0f1a3b5c7d9e1f2a4b6c8d0e2f4a6b8c0d2e4f6a

Signature verification

HMAC SHA256. Verify before you trust.

On setup you receive a secret of the form whsec_followed by 48 random bytes. We sign every request with that secret. The signature header is the concatenated timestamp and request body, HMAC SHA256, hex encoded.

Reject any request with a timestamp more than 5 minutes off yours. Compare signatures with a constant time function. Never log the raw secret.

tsexample
import crypto from "node:crypto";

export function verify(req: { headers: Record<string, string>; rawBody: string }) {
  const header = req.headers["x-detective-signature"] ?? "";
  const parts = Object.fromEntries(
    header.split(",").map((kv) => kv.split("=") as [string, string])
  );
  const timestamp = parts.t;
  const provided = parts.v1;

  // Reject anything older than 5 minutes to block replay.
  const skew = Math.abs(Date.now() / 1000 - Number(timestamp));
  if (skew > 300) return false;

  const signed = `${timestamp}.${req.rawBody}`;
  const expected = crypto
    .createHmac("sha256", process.env.DETECTIVE_WEBHOOK_SECRET!)
    .update(signed)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(provided)
  );
}

Retry policy

Six attempts. Then we stop and tell you.

We retry on any 5xx response or network timeout with exponential backoff. We do not retry on 4xx because that means your endpoint rejected the payload on purpose. After the last retry we mark the delivery failed and surface it in your dashboard so you can replay it manually.

  1. 01immediatelyfirst delivery attempt
  2. 02+30 secondsfirst retry
  3. 03+2 minutesexponential backoff
  4. 04+10 minutesbackoff continues
  5. 05+1 hourbackoff continues
  6. 06+6 hoursfinal retry, then marked failed

A 2xx response within 10 seconds counts as accepted. If your endpoint needs longer, return 200 immediately and queue the work behind it.

Delivery flow

One event, one POST, one acknowledgment.

01

Event fires

analysis.delivered

02

We sign

HMAC SHA256

03

POST to you

https endpoint

04

You ack

200 within 10s

On 5xx or timeout we retry on the schedule above. On 2xx we mark delivered.

Tier availability

Operator tier.

Webhooks are an Operator feature. Daily analyses, the largest ranked pool, and the volume of niche alerts make a signed feed useful in a way the lower tiers do not need. If you need the feed on Hunter, write to us and we will tell you honestly when we open it up.

Starter

Not included

Explorer

Not included

Hunter

Not included

Operator

Included

Build the integration we did not.

Webhooks ship as part of the Operator tier. Sign up now and we will email you the day the endpoint goes live.