Dokumentácia

Webhooky

Posledná aktualizácia: 15. januára 2026

Webhooky doručujú event-driven notifikácie do vášho systému keď sa zmení obsah platformy — nová povinnosť, schválený zmenový návrh, blížiaci sa termín. Každý payload je podpísaný HMAC SHA-256.

1. Eventy

  • obligation.published — nová povinnosť bola publikovaná
  • obligation.updated — zmena v existujúcej povinnosti
  • obligation.deprecated — povinnosť bola označená ako neaktuálna
  • change_proposal.approved — admin schválil návrh zmeny
  • deadline.upcoming — termín do 30/14/7/1 dní (per company)
  • statute.created — nový právny predpis pridaný do katalógu

2. Registrácia subscription

POST /api/v1/webhooks/subscriptions s body:

{
  "url": "https://your-app.example.com/webhooks/clg",
  "events": ["obligation.published", "obligation.updated"],
  "active": true
}

Response obsahuje secret (zobrazený iba raz) — uložte si ho. Tento tajomný kľúč slúži na overenie HMAC podpisu pri každom doručenom payload-e.

3. Payload formát

POST /your-receiver
Content-Type: application/json
X-CLG-Event: obligation.published
X-CLG-Delivery-ID: del_a1b2c3d4
X-CLG-Signature-256: sha256=7f3c8e9d...
X-CLG-Timestamp: 1719859200

{
  "event": "obligation.published",
  "deliveryId": "del_a1b2c3d4",
  "occurredAt": "2026-01-15T10:30:00.000Z",
  "data": {
    "id": 247,
    "title": "Štvrťročný report o flexibilnej kapacite",
    "type": "FIXED",
    "deadline": { "raw": "do 15. dňa po skončení Q", "date": null },
    "_links": {
      "self": "https://compliance.capitol-legal.com/api/v1/obligations/247",
      "web": "https://compliance.capitol-legal.com/obligations/247"
    }
  }
}

4. Overenie HMAC podpisu

Kanonická správa = timestamp + "." + raw_body. HMAC SHA-256 s vaším secret. Porovnanie konstantnou-časovou funkciou (timing-safe).

Node.js / TypeScript receiver

import crypto from 'node:crypto';
import express from 'express';

const app = express();
const SECRET = process.env.CLG_WEBHOOK_SECRET!;

// IMPORTANT: získať raw body PRED akýmkoľvek JSON parserom
app.post(
  '/webhooks/clg',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const sig = req.header('X-CLG-Signature-256') ?? '';
    const ts = req.header('X-CLG-Timestamp') ?? '';
    const body = req.body as Buffer;

    // Replay protection — odmietni eventy staršie ako 5 min
    const ageSec = Date.now() / 1000 - Number(ts);
    if (!Number.isFinite(ageSec) || Math.abs(ageSec) > 300) {
      return res.status(400).send('stale timestamp');
    }

    const expected =
      'sha256=' +
      crypto
        .createHmac('sha256', SECRET)
        .update(`${ts}.${body.toString('utf8')}`)
        .digest('hex');

    const ok = crypto.timingSafeEqual(
      Buffer.from(sig),
      Buffer.from(expected),
    );
    if (!ok) return res.status(401).send('bad signature');

    const event = JSON.parse(body.toString('utf8'));
    console.log('CLG event:', event.event, event.data);

    // Odpovedz 2xx do 5 sekúnd, inak retry policy stop
    res.status(200).end();
  },
);

app.listen(3001);

5. Retry policy

Pri neúspešnom doručení (HTTP status >= 400 alebo timeout 5s) opakujeme s exponenciálnym backoff-om:

  • 1. retry — po 30 sekundách
  • 2. retry — po 5 minútach
  • 3. retry — po 30 minútach
  • 4. retry — po 6 hodinách
  • 5. retry — po 24 hodinách

Po 5 neúspešných pokusoch endpoint auto-deactivuje. Manuálnu reaktiváciu urobíte v /account/webhooks alebo cez API. Posledných 30 dní deliveries je viditeľných v UI s payload + status pre debugging.

6. Bezpečnostné odporúčania

  • Vždy overujte HMAC podpis pred spracovaním payload-u.
  • Implementujte idempotency cez deliveryId — opakovaný retry doručí ten istý event s rovnakým ID.
  • Receiver endpoint nech beží len cez HTTPS (HTTP 1.1+). Self-signed certifikáty sú odmietnuté.
  • Whitelist náš egress IP rozsah (nájdete v /status) ak váš firewall obmedzuje inbound traffic.
  • Tajomný kľúč nikdy nelogujte ani neukladajte do repozitára. Použite environment variable alebo secret manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault).