Real-time webhooks for company events.
Subscribe to filings, ownership changes, status flips, and news across US, SE, NO, FI, UK, DK. Idempotent, signed, retried.
What we deliver.
Every event is a small, flat JSON object posted to your endpoint with an HMAC-SHA256 signature. No polling, no diffing, no schema drift.
POST https://app.example.com/hooks/regna X-Regna-Signature: sha256=7c2f9b... { "event_id": "evt_01HW8...", "event_type": "ownership.changed", "delivered_at": "2026-05-05T12:34:56Z", "data": { "org_nr": "5567037485", "name": "Spotify AB", "change": { "holder_name": "Daniel Ek", "previous_pct": 7.4, "current_pct": 9.8 } } }
Each event is delivered at-least-once. Use event_id for idempotency.
Event types.
Six event families. Subscribe to any combination, scoped to specific companies or to the full universe.
Verify signatures.
Every delivery carries an X-Regna-Signature: sha256=... header. Compute the HMAC over the raw request body with your subscription secret and compare in constant time.
import crypto from 'crypto' const sig = req.headers['x-regna-signature'].split('=')[1] const expected = crypto.createHmac('sha256', WEBHOOK_SECRET) .update(req.rawBody).digest('hex') if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) { return res.status(401).end() }
import hmac, hashlib sig = request.headers["X-Regna-Signature"].split("=")[1] expected = hmac.new( WEBHOOK_SECRET.encode(), request.body, hashlib.sha256, ).hexdigest() if not hmac.compare_digest(sig, expected): return Response(status=401)
import ( "crypto/hmac" "crypto/sha256" "encoding/hex" "strings" ) sig := strings.SplitN(r.Header.Get("X-Regna-Signature"), "=", 2)[1] mac := hmac.New(sha256.New, []byte(webhookSecret)) mac.Write(rawBody) expected := hex.EncodeToString(mac.Sum(nil)) if !hmac.Equal([]byte(sig), []byte(expected)) { http.Error(w, "unauthorized", 401) return }
Always compare with a constant-time function (timingSafeEqual, hmac.compare_digest, hmac.Equal). String equality leaks the secret one byte at a time.
Manage subscriptions.
One REST endpoint creates, lists, updates, and deletes subscriptions. Scope to specific org numbers or omit the filter to receive every event for the types you pick.
# register a subscription:
curl https://regnaverkt.com/api/v1/webhooks \
-H "Authorization: Bearer rk_secret_..." \
-d '{"endpoint_url":"https://app.example.com/hooks/regna",
"event_types":["filing.published","financials.new"],
"entity_ids":["regna:US:0000320193","regna:SE:5560157912"]}'
5 retries with exponential backoff (1m, 5m, 30m, 2h, 12h). After the 5th failure the subscription is paused; we email the account owner.
At-least-once. Dedupe on event_id. Acknowledge with any 2xx within 10 seconds; everything else is treated as a failure.
Render events in your app.
<ChangeFeed /> is a tree-shakeable React component from @regna-verkt/ui. Drop it into a dashboard and it streams the same events your backend receives, filtered to a single company or an explicit list.
import { ChangeFeed } from '@regna-verkt/ui' <ChangeFeed companyId="5567037485" publishableKey={key} eventTypes={["filing.added", "ownership.changed"]} />
For an upcoming-filings calendar use <EventsCalendar /> from the same package - same data layer, calendar layout. Both components ship with TypeScript types and import per-component, so a single feed adds roughly 8 kB gzipped to your bundle.
Subscribe to events.
Webhooks ship on Pro and Business tiers from $149/mo. 14-day trial.