impressum.techDocsAPI-ReferenzPortal

Webhooks

Mit einem Webhook ruft impressum.tech deine URL auf, sobald sich Daten einer Firma oder Domain ändern, die auf der Beobachtungsliste des Webhooks stehen. Du legst ihn im Portal oder über POST /v1/webhooks an. Anlegen, Auflisten, Pflege der Liste und Löschen kosten nichts.

Webhooks gibt es ab dem ersten Kauf eines Credit-Pakets. Ohne Kauf antwortet POST /v1/webhooks mit 403 und dem Code purchase_required; das Portal zeigt dann einen Hinweis.

Beobachtungsliste

Ein Webhook meldet nur Änderungen an Firmen und Domains, die du ihm zuordnest. Ohne Einträge meldet er nichts.

AufrufWirkung
GET /v1/webhooks/{id}/subscriptionsListe lesen
POST /v1/webhooks/{id}/subscriptionsEinträge hinzufügen, Body { "companies": ["c_…"], "domains": ["beispiel.de"] }
DELETE /v1/webhooks/{id}/subscriptionsEinträge entfernen, gleicher Body

Je Aufruf höchstens 100 Einträge, je Konto höchstens 1.000 (über alle Webhooks). Domains werden normalisiert (klein, Punycode); IP-Adressen und Namen ohne öffentliches Suffix lehnt die API ab. Bei domain.linked zählt eine beobachtete Domain oder die beobachtete Firma, der die Domain zugeordnet wird.

curl -X POST https://api.impressum.tech/v1/webhooks/wh_01J…/subscriptions \
  -H "Authorization: Bearer itk_live_…" -H "Content-Type: application/json" \
  -d '{"companies":["c_01J…"],"domains":["muster-baustoffe.de"]}'

Ereignisse

EreignisWann
company.changedEin Feld einer Firma hat sich geändert
company.status_changedDer Status einer Firma hat sich geändert (zusätzlich zu company.changed)
domain.linkedEine Domain wurde einer Firma zugeordnet

Zustellung

Wir senden POST mit JSON an deine URL. Die Nutzdaten enthalten nur IDs und Feldnamen, keine Werte. Die Werte holst du über die API.

{
  "id": "evt_1842_company.changed",
  "type": "company.changed",
  "created_at": "2026-10-11T08:15:00.000Z",
  "data": { "company_id": "c_01J…", "field": "address" }
}

Bei domain.linked lautet data: { "domain": "example.com", "company_id": "c_01J…" }.

Kopfzeilen:

KopfInhalt
Itk-Signaturet=<unix-sekunden>,v1=<hex>
Itk-Event-IdID des Ereignisses; dieselbe ID kann bei Wiederholungen mehrfach ankommen

Antworte mit einem Status 2xx innerhalb von 10 Sekunden. Alles andere zählt als Fehlschlag. Wir wiederholen bis zu 8 Mal mit wachsendem Abstand (ab 30 Sekunden). Nach 20 endgültig gescheiterten Zustellungen in Folge schalten wir den Webhook ab; im Portal erscheint er dann als „abgeschaltet“. Weiterleitungen folgen wir nicht.

Ziele müssen https verwenden und auf öffentliche Adressen zeigen. Wir prüfen die Adresse beim Anlegen und bei jeder Zustellung und verbinden nur zu der geprüften Adresse (keine privaten, internen oder reservierten Netze, auch nicht über IPv6-Schreibweisen wie ::ffff:…, NAT64 oder 6to4). Je Konto sind bis zu 10 aktive Webhooks möglich.

Signatur prüfen

Beim Anlegen zeigen wir das Signiergeheimnis (whsec_…) genau einmal. Die Signatur ist ein HMAC-SHA256 über <t>.<roher Body> mit dem Geheimnis als Schlüssel, hexadezimal. Prüfe:

  1. den HMAC über den unveränderten Body (nicht über erneut serialisiertes JSON),
  2. den Vergleich in konstanter Zeit,
  3. dass t nicht älter als 5 Minuten ist.

Node.js

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

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

// Express: Body roh lesen
// app.post('/hooks/impressum', express.raw({ type: 'application/json' }), (req, res) => {
//   const ok = verifyItkSignature(req.body.toString('utf8'), req.get('Itk-Signature') ?? '', process.env.ITK_WEBHOOK_SECRET);
//   res.sendStatus(ok ? 204 : 400);
// });

Python

import hashlib
import hmac
import time


def verify_itk_signature(raw_body: bytes, header: str, secret: str, tolerance_sec: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    try:
        t = int(parts["t"])
    except (KeyError, ValueError):
        return False
    if abs(time.time() - t) > tolerance_sec:
        return False
    signed = f"{t}.".encode() + raw_body
    expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Doppelte Zustellung

Wiederholungen können dasselbe Ereignis mehrfach liefern. Speichere Itk-Event-Id und verwirf bekannte IDs.