Zum Inhalt springen

Webhook-Referenz

Ereignistypen, Wire-Payload, Signaturprüfung und Zustellvertrag des decidio-Webhook-Systems.

Überblick

Webhooks ermöglichen es Ihrem System, sofort auf Ereignisse in decidio zu reagieren — ohne pollen zu müssen. Wir signieren jede ausgehende Anfrage per HMAC-SHA256, liefern bei Misserfolg automatisch nach und übergeben den kanonischen Payload als JSON.

Wire-Payload

Jedes Ereignis wird als JSON-Objekt mit vier Feldern zugestellt: event_type, timestamp, municipality_id und data. Die data-Struktur richtet sich nach dem Ereignistyp (siehe unten).

Ereignistypen

Aktuell werden fünf Ereignistypen ausgeliefert.

submission.created

Payload-Felder

  • submission_id string
  • reference_number object
  • topic_category_name object
  • topic_source string
  • priority_level string
  • created_at string

Beispiel-Payload

{
  "event_type": "submission.created",
  "timestamp": "2026-01-01T12:00:00.000Z",
  "municipality_id": "00000000-0000-0000-0000-0000000000aa",
  "data": {
    "submission_id": "00000000-0000-0000-0000-000000000001",
    "reference_number": "SUB-2026-000001",
    "topic_category_name": "Verkehr",
    "topic_source": "citizen",
    "priority_level": "normal",
    "created_at": "2026-01-01T12:00:00.000Z"
  }
}

submission.status_changed

Payload-Felder

  • submission_id string
  • reference_number object
  • previous_status string
  • new_status string
  • reason object
  • changed_at string

Beispiel-Payload

{
  "event_type": "submission.status_changed",
  "timestamp": "2026-01-01T12:00:00.000Z",
  "municipality_id": "00000000-0000-0000-0000-0000000000aa",
  "data": {
    "submission_id": "00000000-0000-0000-0000-000000000001",
    "reference_number": "SUB-2026-000001",
    "previous_status": "eingegangen",
    "new_status": "zugeordnet",
    "changed_at": "2026-01-01T12:00:00.000Z"
  }
}

support.threshold_reached

Payload-Felder

  • submission_id string
  • reference_number object
  • support_count number
  • threshold number
  • reached_at string

Beispiel-Payload

{
  "event_type": "support.threshold_reached",
  "timestamp": "2026-01-01T12:00:00.000Z",
  "municipality_id": "00000000-0000-0000-0000-0000000000aa",
  "data": {
    "submission_id": "00000000-0000-0000-0000-000000000001",
    "reference_number": "SUB-2026-000001",
    "support_count": 25,
    "threshold": 25,
    "reached_at": "2026-01-01T12:00:00.000Z"
  }
}

survey.response_received

Payload-Felder

  • survey_id string
  • response_id string
  • received_at string

Beispiel-Payload

{
  "event_type": "survey.response_received",
  "timestamp": "2026-01-01T12:00:00.000Z",
  "municipality_id": "00000000-0000-0000-0000-0000000000aa",
  "data": {
    "survey_id": "00000000-0000-0000-0000-000000000002",
    "response_id": "00000000-0000-0000-0000-000000000003",
    "received_at": "2026-01-01T12:00:00.000Z"
  }
}

sla.escalation_triggered

Payload-Felder

  • submission_id string
  • reference_number object
  • sla_hours number
  • escalated_at string

Beispiel-Payload

{
  "event_type": "sla.escalation_triggered",
  "timestamp": "2026-01-01T12:00:00.000Z",
  "municipality_id": "00000000-0000-0000-0000-0000000000aa",
  "data": {
    "submission_id": "00000000-0000-0000-0000-000000000001",
    "reference_number": "SUB-2026-000001",
    "sla_hours": 48,
    "escalated_at": "2026-01-01T12:00:00.000Z"
  }
}

Signaturprüfung

Jede Anfrage trägt den Header X-Signature: sha256=<hex>. Der Wert ist der HMAC-SHA256 des rohen Request-Bodies (vor JSON-Parsing) mit dem im Admin generierten Secret. Validieren Sie die Signatur server-seitig, bevor Sie den Payload verarbeiten.

Signaturprüfung mit curl + openssl

# Recompute the signature locally and compare
SIGNATURE=$(echo -n "$RAW_BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')
# expected header: X-Signature: sha256=<SIGNATURE>

Signaturprüfung in Node.js

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

export function isValidSignature(rawBody: string, header: string | undefined, secret: string): boolean {
  if (!header?.startsWith('sha256=')) return false
  const expected = createHmac('sha256', secret).update(rawBody).digest('hex')
  const provided = header.slice('sha256='.length)
  try {
    return timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(provided, 'hex'))
  } catch {
    return false
  }
}

Signatur prüfen

Berechnen Sie die HMAC-SHA256-Signatur für einen Beispiel-Payload und Ihr Secret.

Zustellvertrag

decidio versucht jede Auslieferung bis zu vier Mal (1 initial + 3 Wiederholungen) mit Backoff von 1 Minute, 5 Minuten und 30 Minuten. Pro Versuch gilt ein Timeout von 30 Sekunden. Ein HTTP-2xx-Status gilt als „zugestellt“; andere Statuscodes oder Netzwerkfehler lösen die Wiederholung aus. Jede Anfrage trägt User-Agent: decidio-webhooks/1.0.

Verwandte Themen

Tiefer einsteigen: