registercheckby openlaw group
Understand the data

Webhooks

What a monitoring event looks like when it reaches your endpoint, and how to handle it safely.

A monitor is only half of monitoring. The other half is the endpoint we deliver to. This page is the contract: what arrives, what verifies it, and what you must not assume.

Configure an endpoint

Webhooks are configured in API management under Webhooks, not through this API. You give us an HTTPS URL and choose which event types it should receive; leaving the selection empty sends every type.

Each endpoint gets its own signing secret. Keep it — you need it to verify deliveries, and it is the only thing separating a real event from anyone who learns your URL.

What arrives

Deliveries still carry the old shape

The contract publishes the v1 payload below, and the reference documents it. What is delivered today is still the previous shape, because the service that produces these events has not been moved onto the v1 code path yet.

Write your handler against company_id and event_type, which exist in both, and re-read the company rather than trusting any other field. The two shapes agree on everything a correct handler needs.

Delivered today

{
  "event_type": "ADDRESS_CHANGE",
  "company_name": "Beispiel GmbH",
  "company_id": "c359aa06-1ac0-4dab-9c60-d5c69a06ff2c",
  "event_date": "2026-09-15",
  "event_data": {
    "field": "full_address",
    "old": "Hauptstraße 1, 10115 Berlin",
    "new": "Friedrichstraße 200, 10117 Berlin",
    "status": null,
    "content": null
  },
  "created_at": "2026-09-15T18:42:11.930000"
}
FieldNotes
event_typeThe old uppercase vocabulary — ADDRESS_CHANGE, REPRESENTATIVE_ADDED and so on.
company_nameThe name at the time the event was raised, not necessarily the current one.
company_idThe id to re-read. This is the field you actually act on.
event_dateWhen the change was dated in the register.
event_data.fieldWhich field changed. null for event types that are not field-level.
event_data.old / .newThe values, where we have both. old is null on an addition.
created_atWhen we raised the event. Not when the change happened — see detection latency.

event_data is always present, but every field inside it may be null. Read it defensively rather than destructuring.

What it becomes

{
  "id": "6ba7b810-9dad-41d1-80b4-00c04fd430c8",
  "object": "event",
  "type": "company.address.changed",
  "created_at": "2026-09-15T18:42:11Z",
  "effective_date": "2026-09-15",
  "monitor_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "company": { "object": "company", "id": "c359aa06-1ac0-4dab-9c60-d5c69a06ff2c", "name": "Beispiel GmbH" },
  "change": { "field": "address", "previous": "Hauptstraße 1, 10115 Berlin", "current": "Friedrichstraße 200, 10117 Berlin" },
  "officer": null
}

Three things change that are worth planning for: type uses the same dotted vocabulary as monitors, the body carries its own id so you no longer have to deduplicate on the svix-id header, and monitor_id tells you which of your monitors fired.

Verifying a delivery

Delivery is handled by Svix, which implements the Standard Webhooks specification. Three headers come with every request:

HeaderMeaning
svix-idThe unique message identifier.
svix-timestampDelivery timestamp, used to reject replays.
svix-signatureHMAC signature over the id, timestamp and body.

Verify with the official library rather than by hand — it does constant-time comparison and the timestamp tolerance for you:

import { Webhook } from 'svix';

const wh = new Webhook(process.env.REGISTERCHECK_WEBHOOK_SECRET!);

app.post('/hooks/registercheck', express.raw({ type: 'application/json' }), (req, res) => {
  let event;
  try {
    event = wh.verify(req.body, {                 // the RAW body, not the parsed object
      'svix-id': req.headers['svix-id'] as string,
      'svix-timestamp': req.headers['svix-timestamp'] as string,
      'svix-signature': req.headers['svix-signature'] as string,
    });
  } catch {
    return res.status(400).end();                 // unverified: do not process
  }

  res.status(200).end();                          // acknowledge, then work
  void handle(req.headers['svix-id'] as string, event);
});

Signature verification needs the raw request body. A JSON body-parser mounted earlier will re-serialise it and the signature will not match.

Deduplicate on svix-id, not on the body

There is no event_id in the request body. The identifier to deduplicate on is the svix-id header.

We do send an event id to Svix, but it is a sender-side idempotency key — it stops us from raising the same event twice and never appears in what you receive. Reading req.body.event_id gives you undefined, and a deduplication check against undefined silently passes for every delivery.

Assume at-least-once delivery: a slow or failing endpoint is retried, and a retry carries the same svix-id.

Treat the payload as a signal

event_data.new tells you what we saw at detection time. It is not a substitute for the company record, and it is not guaranteed to still be current when you process it. Re-read the company and act on that:

event arrives  →  verify  →  dedupe on svix-id  →  GET /companies/{company_id}  →  apply

The track changes guide walks through this end to end.

On this page