Skip to content
LR Defender
Book a demo

Webhooks

Get an event on your server when an identification comes back high risk or anomalous. Every delivery is signed with your endpoint's secret and retried if it fails.

Overview

A webhook is an address on your server that we call with a JSON body when an event happens. Each endpoint has its own secret, and every delivery carries an HMAC-SHA256 signature made with it, so your server can check the request came from us. Webhooks add to the verdict you fetch in the quick start; they do not replace it.

Create an endpoint

Add an endpoint under Webhooks in the dashboard, or from your server with your secret key:

POST/api/tenant/webhooksSecret key
curl -X POST https://api.lrdefender.lightningresearch.ai/api/tenant/webhooks \  -H "X-API-Key: $LR_SECRET_KEY" \  -H "Content-Type: application/json" \  -d '{"url": "https://app.example.com/webhooks/lr-defender", "events": ["*"], "name": "Production"}'
urlstringRequired
Where to deliver. HTTPS or HTTP on the public internet; loopback and private addresses are refused.
eventsstring[]Optional
The events to receive, or ["*"] for every event. An endpoint with no events receives nothing.
namestringOptional
A label for the dashboard.
secretstringOptional
Your own signing secret. Leave it out and we generate one.

Events

fraud.high_risk
An identification's risk level is high or critical.
anomaly.detected
Anomaly detection flags an identification.
webhook.test
You send a test from the dashboard or the test endpoint.

Every delivery is a POST with a JSON body of three fields: event, timestamp and data. The X-Webhook-Event header repeats the event name. Example bodies:

{  "event": "fraud.high_risk",  "timestamp": "2026-09-26T10:04:12.000Z",  "data": {    "deviceId": "da59f482997ad9359d6e0662",    "tenantId": "5f1c09a2b7e4d3c8a1f60b92",    "riskLevel": "high",    "fraudScore": 0.63,    "recommendation": { "action": "challenge", "reasonCodes": ["behavior_bot_high"] }  }}

Verify the signature

The X-Webhook-Signature header is the hex HMAC-SHA256 of the raw request body, keyed with the endpoint's secret. Compute the same value over the body exactly as received, compare in constant time, and answer 401 when they differ.

import crypto from "node:crypto";import express from "express"; const app = express(); // Read the raw body: the signature covers the exact bytes we sent.app.post("/webhooks/lr-defender", express.raw({ type: "application/json" }), (req, res) => {  const expected = crypto    .createHmac("sha256", process.env.LR_WEBHOOK_SECRET)    .update(req.body)    .digest("hex");  const received = req.get("X-Webhook-Signature") ?? "";  const valid =    received.length === expected.length &&    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));  if (!valid) return res.status(401).end();   const { event, data } = JSON.parse(req.body.toString("utf8"));  // event is "fraud.high_risk", "anomaly.detected" or "webhook.test"  res.status(200).end();});

Delivery and retries

  • A delivery succeeds when your endpoint answers with a 2xx status within 10 seconds.
  • A failed delivery is retried with growing delays, up to five attempts in all.
  • Every attempt is logged. The dashboard lists each endpoint's deliveries and can resend a failed one.

Answer quickly and do slow work afterwards, and make your handler safe to run twice for the same event: a retry can deliver an event you already processed.

Test your endpoint

Send a webhook.test event from the dashboard, or from your server:

POST/api/tenant/webhooks/{webhookId}/testSecret key

To receive deliveries on a development machine, expose it through a tunnel with a public HTTPS address and register that address as the endpoint.

Get a verdict in your own app.

After a demo call, we set up your account and email you a link to set your password. It starts with a 90-day free trial on the Pro plan's limits, with no card.