Skip to content
Apier.no
Guides

How to get change alerts for Norwegian companies

Watch up to 100 Norwegian companies and get a signed webhook when their signing rules, role holders, status or VAT registration change in Brønnøysund's registers, with before and after values and both dates.

[Cite this as: Apier.no Docs v0.1.0 — last updated 2026-10-30]

Change alerts send your server a signed webhook when something changes for a company you watch:

Event typeWhen it fires
signing_rule_changedThe registered signature (signaturrett) or prokura rules change.
role_addedA role holder is added to the board or as owner of a sole proprietorship.
role_removedA role holder is removed.
status_changedThe company's status changes, for example to bankrupt, in liquidation, forcibly dissolved or deleted.
vat_registration_changedThe company is registered in, or removed from, the VAT register.

Every event carries the before and after values, the effective date where Brønnøysund gives one, the date Apier observed the change, the source and the id of the archived change it comes from. Events never name a person: a role event says which role was added or removed, and a signing event lists the role labels and signing rules, not who holds them. To see who holds a role now, call GET /api/v1/company/{org}/authority. An event reports what changed in the register; it is not a statement about who may sign.

Alerts cover companies Apier mirrors from the Brønnøysund update feeds. The archive starts on 2026-07-30, and a change is usually delivered within about an hour of Apier observing it.

Step 1 — Check that your account can use change alerts

Change alerts follow the Annual Accounts Monitor's rules and price: each watched company is charged the Monitor's monthly price from your wallet once per calendar month (Europe/Oslo), and once only even when you also monitor that company's annual accounts. Deliveries cost nothing extra. Until per-company wallet billing is switched on, change alerts are available to existing Professional and Enterprise subscriptions to the end of their period; other accounts get 403 ACCOUNTS_MONITOR_NOT_AVAILABLE. See pricing.

Step 2 — Add the first company

The watchlist is managed from a dashboard session. The first company creates it, so send the webhook URL and the id of the account key whose wallet and spend caps pay the monthly charge:

curl -X POST https://www.apier.no/api/v1/account/watchlist/companies \
  -H "Content-Type: application/json" \
  --cookie "<your dashboard session cookie>" \
  -d '{"org_number":"999999999","webhook_url":"https://<your-webhook-endpoint>","api_key_id":"<your account key id>"}'

The 201 response carries webhook_secret, the HMAC signing secret. It is shown once: store it now. Add more companies with only org_number (at most 100; the 101st answers 409 WATCHLIST_LIMIT_REACHED). Send event_types to watch a subset of the five event types. Adding a company you already watch changes nothing.

Step 3 — Verify each delivery

Each delivery is a POST to your URL with the header x-apier-signature: t=<unix seconds>,v1=<hex>. Recompute the signature over the timestamp, a dot and the raw request body with your secret, and compare in constant time. Refuse a timestamp older than five minutes:

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, header: string, secret: string): boolean {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const t = Number(parts.t);
  if (!Number.isInteger(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex");
  const given = Buffer.from(String(parts.v1 ?? ""), "hex");
  const want = Buffer.from(expected, "hex");
  return given.length === want.length && timingSafeEqual(given, want);
}

The body's change object has entity_type: "company_alert", entity_id (the org number) and field_path /<event type>; the event is in after_value:

{
  "change": {
    "entity_type": "company_alert",
    "entity_id": "999999999",
    "field_path": "/status_changed",
    "after_value": {
      "status_changed": {
        "event_type": "status_changed",
        "org_number": "999999999",
        "before": "active",
        "after": "bankrupt",
        "effective_date": "2026-10-29",
        "observed_date": "2026-10-30",
        "source": "brreg",
        "source_change_id": "11111111-2222-4333-8444-555555555555"
      }
    }
  }
}

Answer with any 2xx status. Other answers are retried with backoff (1 minute, 5 minutes, 15 minutes, 1 hour, 6 hours, 24 hours), and the endpoint is disabled after six consecutive 4xx answers, with an email to the account.

Step 4 — Read and change the watchlist

GET /api/v1/account/watchlist lists the watched companies and their status. A company whose monthly charge the wallet balance or a spend cap refused is paused_unpaid or paused_spend_cap: it gets no alerts, and your balance is never made negative. Top up or raise the cap, then add the company again to resume it.

DELETE /api/v1/account/watchlist/companies/999999999 removes a company. Removing a company you do not watch answers 200 with removed: false. Removing the last company ends the watchlist; the next add creates a new one with a new secret. A month already charged is not refunded.

The same events are listed by GET /api/v1/changes?entity_id=999999999.

Step 5 — Test your receiver in the sandbox

GET /api/v1/sandbox/watchlist/events returns one synthetic alert of each event type, shaped exactly like the change object of a real delivery. It accepts the sandbox bearer, needs no watchlist and costs nothing. The sandbox returns events by polling only and never sends a webhook.

Building with an LLM? Read llms.txt for agent-oriented integration guidance.