registercheckby openlaw group
Guides

Track changes

Replace a polling loop with a monitor and a webhook.

The shape of it

monitor once  →  we re-read the register  →  event fires  →  your webhook  →  you re-read the company

You monitor a company. We detect that its register entry moved. Your destination gets told. You fetch the new state.

A monitor follows the companies you name. To follow changes across every company -- all new managing directors in Bavaria, every insolvency -- poll the register-event feed instead: Follow register changes.

Monitor a company

import uuid

def watch(court: str, register_type: str, number: str,
          events=("*",), crm_id: str | None = None) -> str:
    r = session.post(
        f"{BASE}/monitors",
        headers={"Idempotency-Key": str(uuid.uuid4())},   # reuse it if you retry this call
        json={
            "register": {"court": court, "type": register_type, "number": number},
            "event_types": list(events),
            "metadata": {"crm_id": crm_id} if crm_id else {},
        },
    )
    if r.status_code == 409 and r.json()["code"] == "conflict":
        return r.json()["existing_id"]                    # already watching it
    r.raise_for_status()
    return r.json()["id"]

watch("München", "HRB", "999999", events=("representation", "capital"), crm_id="0015g00000XyZ")

No search first: the register identity names the company. No list-then-check either: a second monitor on the same company answers 409 with the existing monitor's id, and the Idempotency-Key makes a retry after a timeout safe — creating a monitor costs 10 credits.

Narrow the events

* is the default and it is noisy. Monitor what you will act on:

You care aboutMonitor
A counterparty's solvencyinsolvency, dissolution, capital
Who can signrepresentation
Change of controlshareholders — accepted, but not delivered yet: the monitor lists these in unavailable_event_types
Keeping records tidyidentity, registered_office, conversion

"Who can sign" is one set of types: an authorised signatory holds a role here, so a grant of Prokura and a board appointment both raise company.role.added, and data.role_type says which.

One list names every event type (GET /event-types); monitorable says which a monitor can ask for. A register entry keeps its name in the history and on a monitor, and four types are monitoring's own. Shareholders are reported one by one (company.shareholder.added, company.shareholding.changed, company.shareholder.removed), where the history records a newly filed shareholder list once (company.shareholder_list.changed). And company.financial_statement.published comes from the Bundesanzeiger and has no counterpart in the register history.

Change the selection later with PATCH /monitors/{id}, which touches only what you send — so {"status": "paused"} stops delivery without losing your event types.

Handle the webhook

app.post('/hooks/registercheck', async (req, res) => {
  const delivery = verify(req);        // see Webhooks: raw body + the three svix-* headers
  res.status(200).end();               // acknowledge first, work after

  if (await alreadyProcessed(delivery.id)) return;      // delivery.id is the svix-id; a retry repeats it

  for (const event of delivery.events) {                // one for an instant destination, a period's for a digest
    const fresh = await fetchCompany(event.subject.id); // the payload is a signal, not state
    await applyChange(event.subject.id, event.type, fresh);
  }
  await markProcessed(delivery.id);
});

Three rules, in order of how much trouble they save you:

  1. Acknowledge immediately. A slow handler is a retried handler.
  2. Deduplicate on the delivery id (also the svix-id header). Assume at-least-once delivery; a retry repeats it. See Webhooks.
  3. Re-read the company. Treat the event as "something changed", not as the new value.

What this is not

Detection runs on a cycle against the register, and the register itself lags the real world by days or weeks. Expect to hear about a change a day or two after it is published, and do not build anything that needs to know within the hour.

Housekeeping

Only creating a monitor costs anything; listing, reading, updating and deleting are free. So read GET /monitors whenever you want the truth rather than trusting a local index, and delete what you no longer watch — the cost of a monitor is the 10 credits you already paid, not an ongoing charge.

On this page