Hilfecenter & Dokumentation

Alle Anleitungen und Antworten auf einen Blick, durchsuche die Dokumentation oder filtere nach Thema.

55 Artikel

Fehlende Kursteilnehmer unter Aktivitäten

Wenn ein Teilnehmer im Kurs angezeigt wird, aber in einer einzelnen Aktivität fehlt, kannst du das Problem meist schnell selbst beheben: Öffne den Kurs unter «Aktivitäten → Kurs verwalten» und klicke auf Speichern, damit die Teilnehmer synchronisiert werden.
Artikel lesen →

Kursteilnehmer nachführen

In diesem Artikel erfährst du, dass Kursteilnehmer nicht automatisch aus Gruppen übernommen werden; du kannst Teilnehmer manuell pflegen oder die Selbstanmeldung aktivieren. Trainer können Teilnehmerlisten jederzeit bearbeiten.
Artikel lesen →

Kurse mit der NDS-Datenbank (J&S) synchronisieren

Du kannst Kurs-, Teilnehmer- und Anwesenheitsdaten aus DigitalMembers als NDS-kompatible CSV exportieren und manuell in die NDS-Datenbank (BASPO) importieren; eine vollautomatische Synchronisation ist wegen fehlender API nicht möglich.

Artikel lesen →

Mitteilungen (Kampagnen) erstellen und versenden

Du kannst Mitteilungen an Mitglieder per E-Mail, WhatsApp, Push oder Brief erstellen, gestalten, testen, zeitlich planen und auswerten. Die Anleitung zeigt Schritt-für-Schritt, wie du Kampagnen anlegst, Inhalte im Drag-&-Drop-Editor erstellst, Test-Sendungen machst und Empfänger sowie Versandoptionen festlegst.
Artikel lesen →

Rechnungen stornieren

Du kannst Rechnungen je nach Status löschen, stornieren oder wiederherstellen: unbezahlte/unschickte Rechnungen löschen; versendete/bezahlt Rechnungen stornieren; stornierte Rechnungen wiederherstellen; und Erinnerungen für ehemalige Mitglieder entfernen.
Artikel lesen →

Sponsoring Modul – Getting Started

Das Sponsoring-Modul hilft dir, Sponsoringprojekte zentral zu verwalten: Projekte, Pakete, Sponsoren, Rechnungen und Kampagnen in einem Workflow. Es ist aktuell noch in Beta.
Artikel lesen →

Domains in den Organisationseinstellungen verwalten

Vereins-Domain in DigitalMembers hinterlegen, SPF-/DKIM-/DMARC-Records eintragen und verifizieren — Voraussetzung für hohe Zustellrate und Phishing-Schutz.
Artikel lesen →

Mehrwertsteuer einrichten und die MWST-Abrechnung erstellen

MWST in DigitalMembers einrichten und die MWST-Abrechnung nach Saldosteuersatz erstellen, kontrollieren und bei der ESTV einreichen.
Artikel lesen →

Admin-Berechtigungen für Mitglieder verwalten

Vergib einzelnen Mitgliedern gezielt Admin-Rechte, etwa für Mitgliederverwaltung, Rechnungen, Kampagnen oder Dokumente. Hier erfährst du, was jede Rolle genau kann.
Artikel lesen → 49

Allgemeine Geschäftsbedingungen (AGB) konfigurieren

Mit der AGB-Funktion kannst du verbindliche Bedingungen erstellen, in mehreren Sprachen hinterlegen und Mitgliedern bei Formularen/Kursanmeldungen zur aktiven Zustimmung vorlegen; Einwilligungen werden protokolliert und bleiben bei Änderung bestehen.
Artikel lesen → 23

Bankkonto pro Rechnung einrichten

Du kannst für einzelne Rechnungen, Vorlagen und Module ein abweichendes Bankkonto mit IBAN oder QR-IBAN hinterlegen; bleibt das Feld leer, wird das Standard-Bankkonto aus den Buchhaltungseinstellungen verwendet.
Artikel lesen →

Datenaufbewahrung einrichten

Du kannst festlegen, wie lange Versandprotokolle und Anhänge gespeichert bleiben; nach Ablauf werden diese automatisch gelöscht, Rechnungen und Mitgliederdaten bleiben erhalten. Die Bereinigung läuft wöchentlich und die Standardfrist ist 730 Tage (inaktive Organisationen: 90 Tage).
Artikel lesen →

Webhooks: Ereignisse automatisch an deine Systeme senden

APIIntegrationenSicherheit

Mit Webhooks lässt du dein eigenes System automatisch auf Ereignisse in DigitalMembers reagieren — ohne ständig nachzufragen. Sobald sich etwas ändert, schicken wir dir eine signierte Nachricht an eine von dir hinterlegte Adresse. Du prüfst sie, bestätigst den Empfang und lädst bei Bedarf die Details über die API nach.

So funktioniert es

Tritt in deiner Organisation ein Ereignis ein, senden wir eine POST-Anfrage mit einem kompakten Datensatz an deine hinterlegte Adresse. Du prüfst die Signatur, antwortest mit einem Status im 2xx-Bereich und verarbeitest die Nachricht. Antwortest du nicht mit 2xx, wiederholen wir die Zustellung automatisch mit wachsenden Abständen — du musst nichts von Hand nachtriggern.

Webhook einrichten

Webhooks verwaltest du unter Organisation → Einstellungen → Webhooks. Pro Webhook hinterlegst du eine HTTPS-Adresse und wählst die Ereignisse aus, die du abonnieren möchtest.

Die Absicherung — Signatur und optional OAuth2 — konfigurierst du einmalig pro Organisation im Bereich „Authentifizierung". Sie gilt für alle deine Webhooks. Aktiviere mindestens eine Absicherung.

Verfügbare Ereignisse

Aktuell stehen diese Ereignisse zur Verfügung:

  • member.changed — etwas rund um ein Mitglied hat sich geändert. Das Ereignis wird ausgelöst, wenn ein Mitglied erstellt, geändert oder gelöscht wird, aber auch, wenn sich ein Feld oder eine Feldzuweisung ändert. Welcher Objekttyp betroffen ist, steht im Feld data.model (members.member, members.field oder members.fieldassignment); die konkrete Aktion im Feld data.operation (created, updated, deleted).
  • registration.changed — eine Anmeldung hat sich geändert. Das Ereignis wird ausgelöst, wenn über ein öffentliches Formular eine neue Anmeldung eingeht, wenn ein Mitglied eine Profiländerung einreicht oder anpasst, oder wenn eine Anmeldung angenommen oder abgelehnt wird. Im Feld data.model steht registration.registration, die konkrete Aktion im Feld data.operation (created, updated). Über data.ids lädst du die betroffene Anmeldung bei Bedarf über die API nach.

Aufbau der Nachricht

Jede Zustellung hat denselben Aufbau: einen Umschlag mit Metadaten und ein data-Objekt, das die betroffenen Objekte beschreibt.

{
  "id": "1efdff58-1111-1111-1111-111111111111",
  "event": "member.changed",
  "version": "v2",
  "created_at": "2026-07-05T10:15:00+00:00",
  "org_id": "1efdff58-2222-2222-2222-222222222222",
  "data": {
    "ids": ["1efdff58-0000-0000-0000-000000000000"],
    "model": "members.member",
    "service": "members",
    "operation": "updated"
  }
}
  • id — eindeutige Kennung der Nachricht. Bleibt bei Wiederholungen gleich; verarbeite jede id nur einmal.
  • event — der Ereignistyp.
  • version — Version des Nachrichten-Formats. Bei einer grundlegenden Änderung erhöhen wir sie.
  • created_at — Zeitpunkt des Ereignisses.
  • org_id — die Organisation, zu der das Ereignis gehört.
  • data.ids — die Kennungen der betroffenen Objekte als Liste. Damit lädst du die Details über die API nach.
  • data.model / data.service — Objekttyp und zuständiger Bereich. data.model sagt dir, worauf sich data.ids beziehen: members.member (Mitglieder), members.field (Felder), members.fieldassignment (Feldzuweisungen) oder registration.registration (Anmeldungen). Lade je nach Typ das passende Objekt über die API nach.
  • data.operation — die Aktion: created, updated oder deleted. Bei deleted ist das Objekt über die API nicht mehr abrufbar.

Warum die Nachricht keine Personendaten enthält

Die Nachricht sagt dir bewusst nur, was sich geändert hat und wo — niemals die Inhalte selbst. Namen, Adressen oder andere Personendaten sind nie enthalten. Das hat mehrere Gründe:

  • Die Absicherung ist optional. Ein Webhook kann auch ohne OAuth2 betrieben werden. Damit selbst dann nichts Sensibles nach aussen gelangt — etwa wenn eine Adresse versehentlich falsch konfiguriert ist — enthält die Nachricht grundsätzlich keine Personendaten.
  • Du behältst die Kontrolle über deine Daten. Die eigentlichen Details holst du gezielt über die API ab, mit deinem eigenen Zugang. Ein kompromittierter Empfänger verrät so keine Mitgliederdaten.
  • Die Reihenfolge ist nicht garantiert und eine Nachricht kann in seltenen Fällen doppelt eintreffen. Behandle die Nachricht darum als Auslöser, nicht als endgültige Wahrheit: lade bei Bedarf den aktuellen Stand über die API nach, statt dich allein auf den Inhalt der Nachricht zu verlassen.

Signatur prüfen

Bei aktivierter Signatur trägt jede Zustellung zwei Kopfzeilen. Damit weist du nach, dass die Nachricht von DigitalMembers stammt und unterwegs nicht verändert wurde — auch wenn dein Endpoint sonst keine eigene Authentifizierung hat.

X-Webhook-Signature: 5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
X-Webhook-Timestamp: 1720087200
  • Die Signatur ist ein HMAC-SHA256 über die Zeichenkette {timestamp}{body} mit deinem Signaturschlüssel (in den Webhook-Einstellungen über „Signaturschlüssel kopieren" abrufbar).
  • Berechne den HMAC über {X-Webhook-Timestamp}{empfangener Body} und vergleiche ihn zeitkonstant mit X-Webhook-Signature.
  • Verwirf Nachrichten, deren Zeitstempel älter als 5 Minuten ist (Schutz vor Wiederholungsangriffen).
  • Prüfe immer gegen den rohen, unveränderten Body — verarbeite den Inhalt erst nach erfolgreicher Prüfung.
import hashlib
import hmac
import time

def signature_is_valid(secret, signature, timestamp, body, tolerance_seconds=300):
    if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > tolerance_seconds:
        return False
    expected = hmac.new(secret.encode(), timestamp.encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
Dein Signaturschlüssel ist wie ein Passwort. Bewahre ihn sicher auf, gib ihn nicht weiter und lege ihn nie in öffentlich zugänglichem Code ab. Rotiere ihn sofort, wenn der Verdacht besteht, dass er nach aussen gelangt ist — das geht jederzeit in den Webhook-Einstellungen. Für Schäden aus einem geleakten oder unsorgfältig aufbewahrten Signaturschlüssel übernimmt DigitalMembers keine Verantwortung; die sichere Aufbewahrung liegt allein in deiner Verantwortung.

OAuth2 (optional)

Zusätzlich oder alternativ zur Signatur kann jede Zustellung ein OAuth2-Token tragen. Hinterlege dazu Token-Adresse, Client-ID und Client-Secret deines eigenen Identity-Providers. Vor jeder Zustellung holt DigitalMembers per Client-Credentials-Grant ein Token bei deiner Token-Adresse ab und sendet es als Authorization: Bearer <token> mit. Da das Token von deinem eigenen Provider ausgestellt wird, prüfst du es an deinem Endpoint gegen genau diesen Provider.

Beispiel: Webhook-Empfänger mit FastAPI

Ein vollständiger Empfänger liest den rohen Body, prüft die Signatur und verarbeitet die Nachricht erst nach bestandener Prüfung.

import hashlib
import hmac
import json
import time

from fastapi import FastAPI, Header, HTTPException, Request

WEBHOOK_SECRET = "whsec_dein_signaturschluessel"
SIGNATURE_TOLERANCE_SECONDS = 300  # 5 Minuten

app = FastAPI()


def signature_is_valid(signature, timestamp, body):
    if not signature or not timestamp or not timestamp.isdigit():
        return False
    if abs(time.time() - int(timestamp)) > SIGNATURE_TOLERANCE_SECONDS:
        return False
    expected = hmac.new(WEBHOOK_SECRET.encode(), timestamp.encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)


@app.post("/webhooks/digitalmembers")
async def receive_webhook(request: Request,
                          x_webhook_signature: str | None = Header(default=None),
                          x_webhook_timestamp: str | None = Header(default=None)):
    body = await request.body()          # rohe Bytes lesen, bevor JSON geparst wird
    if not signature_is_valid(x_webhook_signature, x_webhook_timestamp, body):
        raise HTTPException(status_code=401, detail="invalid signature")

    event = json.loads(body)
    if event["event"] == "member.changed":
        model = event["data"]["model"]            # members.member | members.field | members.fieldassignment
        object_ids = event["data"]["ids"]         # Liste der betroffenen Kennungen
        operation = event["data"]["operation"]    # created | updated | deleted
        # Details bei Bedarf über die API nachladen (mit deinem eigenen Zugang)
        handle_member_change(model, object_ids, operation)
    elif event["event"] == "registration.changed":
        registration_ids = event["data"]["ids"]   # betroffene Anmeldungen
        operation = event["data"]["operation"]    # created | updated
        handle_registration_change(registration_ids, operation)

    return {"received": True}

Hast du zusätzlich OAuth2 aktiviert, prüfst du den mitgesendeten Bearer-Token gegen deinen eigenen Identity-Provider und lehnst ungültige Token mit 401 ab.

import jwt  # pip install "pyjwt[crypto]"
from jwt import PyJWKClient

# JWKS deines eigenen Identity-Providers (derselbe, dessen Token-Adresse du hinterlegt hast)
JWKS = PyJWKClient("https://dein-idp.example.com/.well-known/jwks.json")


def bearer_is_valid(authorization):
    if not authorization or not authorization.lower().startswith("bearer "):
        return False
    token = authorization.split(" ", 1)[1]
    try:
        signing_key = JWKS.get_signing_key_from_jwt(token).key
        jwt.decode(token, signing_key, algorithms=["RS256"])  # wirft bei ungültig oder abgelaufen
        return True
    except jwt.InvalidTokenError:
        return False

Zustellung und Wiederholungen

Wir stellen jede Nachricht zuverlässig zu und wiederholen sie bei Problemen automatisch — du musst nichts von Hand nachtriggern.

  • Erwartete Antwort: Dein Endpoint muss innerhalb von 10 Sekunden mit einem Status im 2xx-Bereich antworten. Jede andere Antwort — ein Fehlerstatus, eine Zeitüberschreitung oder eine nicht erreichbare Adresse — gilt als Fehlversuch und löst eine Wiederholung aus.
  • Wiederholungen: Nach dem ersten Versuch wiederholen wir mit wachsenden Abständen: nach 5 Minuten, 15 Minuten, 30 Minuten, 2 Stunden, 6 Stunden und 24 Stunden. Das sind insgesamt 7 Zustellversuche. Antwortet dein Endpoint bei einem davon mit 2xx, gilt die Nachricht als zugestellt und wir hören auf. Kommt auch der letzte Versuch nicht durch, markieren wir die Nachricht als endgültig fehlgeschlagen.
  • Mindestens einmal: Die Zustellung erfolgt „at least once" — eine Nachricht kann in seltenen Fällen doppelt eintreffen. Dedupliziere darum über die id und verarbeite jede nur einmal (Idempotenz).
  • Reihenfolge: Die Zustellreihenfolge pro Webhook ist meist stabil, aber nicht garantiert. Verlasse dich nicht darauf; lade bei Bedarf den aktuellen Stand über die API nach.
  • Von Hand erneut zustellen: Im Zustellprotokoll im Webhook-Detail siehst du zu jeder Nachricht den Antwort-Status und die Zahl der Versuche und kannst einzelne Zustellungen jederzeit erneut auslösen.
  • Automatische Deaktivierung: Schlägt ein Webhook über längere Zeit dauerhaft fehl — rund 20 aufeinanderfolgende Fehlversuche über mindestens eine Woche ohne einen einzigen Erfolg — deaktivieren wir ihn automatisch, damit sich keine Nachrichten an eine tote Adresse stauen. Du siehst das am Webhook-Status und kannst ihn in den Einstellungen wieder aktivieren; dabei wird der Fehlerzähler zurückgesetzt.

Schutz vor Endlosschleifen: Zusätzlich gilt eine grosszügige Obergrenze an Zustellungen pro Stunde und Organisation. Löst dein System auf ein eingehendes Ereignis hin wieder eine Änderung bei uns aus, die ihrerseits ein neues Ereignis erzeugt, kann eine Schleife entstehen; wird die Obergrenze überschritten, stellen wir weitere Ereignisse in dieser Stunde nicht mehr zu — sie werden auch später nicht nachgeliefert. Gleiche den Datenstand in diesem Fall über die REST-API ab. Vermeide darum Rückschreibungen, die dasselbe Ereignis erneut auslösen.

Anforderungen an die Adresse

  • Nur https:// mit einem öffentlich erreichbaren Hostnamen.
  • Antworte schnell mit 2xx und verarbeite aufwändige Logik im Hintergrund, damit du das Zeitlimit nicht reisst.
  • Behandle deinen Signaturschlüssel wie ein Passwort und rotiere ihn bei Verdacht.

Testen

Du musst nicht auf ein echtes Ereignis warten: Sende in den Webhook-Einstellungen ein Test-Event an deinen Endpoint. Im Zustellprotokoll siehst du zu jeder Nachricht den Antwort-Status und kannst einzelne Zustellungen erneut auslösen. So prüfst du deine Signatur- und OAuth-Verifikation von Anfang bis Ende, bevor du live gehst.

Zum Ausprobieren ohne eigenes System kannst du einen Webhook auch direkt auf unseren Test-Empfänger zeigen lassen:

https://signatera.digitalmembers.ch/v2/webhooks/test/{deine-org-id}/

Der Test-Empfänger nimmt jede Zustellung an, prüft die Signatur mit deinem Signaturschlüssel und liefert das Ergebnis im Antwort-Body zurück (signature_present, signature_valid, timestamp_valid).

Verwandte Artikel

Bereit, deinen Verein zu digitalisieren?

Kostenlos testen