Teil des WJ-Kreis-Digital-Standards. Referenz-Installation: WJ Konstanz-Hegau (KNH). Stand: 2026-08-14. Faktenbasis: Inventare in
meta/(live, n8n, repo, knowledge).
Jeder WJ-Kreis hat VereinOnline (VO). Damit ist dieses Kapitel das mit dem größten kreisübergreifenden Wert: Was hier steht, könnt ihr eins zu eins anwenden, auch wenn ihr (noch) keine eigene Nextcloud oder n8n-Instanz betreibt. VO ist in unserer Architektur das System of Record für Mitglieder und Events. Alles andere (Nextcloud, Website, Automatisierung) liest aus VO oder schreibt gezielt dorthin zurück, hält aber nie eine eigene Kopie der Wahrheit. Möglich macht das die VO-API, allerdings mit einigen Verhaltensweisen, die man kennen muss, bevor man ihr Produktivdaten anvertraut. Dieses Kapitel dokumentiert die API-Grundlagen, das Service-User-Konzept mit minimalen Rechten und sämtliche Fallen, die wir in der Referenz-Installation selbst erlitten und gelöst haben.
1. API-Grundlagen
1.1 Charakter der API
Die VO-API ist pull-only. Es gibt keine Webhooks: VO meldet sich nie von selbst, wenn sich ein Mitglied ändert oder ein Event angelegt wird. Synchronisation heißt deshalb immer zeitgesteuertes Polling. Unsere Empfehlung: nicht häufiger als alle 5 Minuten pollen. Rate Limits sind undokumentiert, also behandelt die API pfleglich. In der Referenz-Installation pollt der dichteste Workflow (Foto-Drop) alle 10 Minuten, die übrigen alle 4 Stunden oder seltener.
Aufrufe laufen als HTTP-Requests gegen die VO-Instanz des Kreises mit einem
?api=-Parameter, z. B. ?api=GetMembers oder ?api=GetEvents. Eine vollständige
Matrix der API-Fähigkeiten (GetEvents, CreateRegistration, CreateSubscriber usw.)
liegt in wj/DigitalWorld/vo-integration-capabilities.md.
1.2 URL-Konvention (Verwechslungsgefahr!)
VO betreibt mehrere Umgebungen, und die Namensgebung führt in die Irre:
| Instanz | Pattern |
|---|---|
| Test/Sandbox | https://test.vereinonline.org/<KREIS>/?api=... |
| Staging via VO-Hauptdomain | https://www.vereinonline.org/<KREIS>/?api=... (trotz "www" NICHT Prod!) |
| Prod (Live-Daten) | Custom-Domain des Kreises ohne Kreis-Prefix, z. B. https://www.wj-konstanz-hegau.de/?api=... |
Merkt euch besonders die zweite Zeile: Die URL mit www.vereinonline.org sieht aus
wie Produktion, ist es aber nicht. Wer dort testet und sich wundert, warum die
Live-Daten fehlen, sitzt dieser Falle auf.
1.3 Authentifizierung
Das Token hat das Format A/<username>/<md5(passwort)> und lässt sich lokal
generieren. Übergabe entweder als Authorization-Header oder als URL-Parameter
&token=. Zwei Konsequenzen daraus:
- MD5 ist kryptografisch gebrochen, aber VO-Stand der Technik. Kompensiert das mit einem starken, langen Passwort pro Service-User und ausschließlich HTTPS-Transport. Beides ist Pflicht, nicht Kür.
- Das Token hängt am Passwort-Hash. Token-Rotation heißt also schlicht: Passwort des Service-Users wechseln, Token neu generieren, in der Automation (z. B. n8n-Credential) hinterlegen.
Achtung, das Auth-Verhalten hat eine gefährliche Eigenheit (stiller Fallback auf anonym), die in Abschnitt 3.1 ausführlich beschrieben ist. Lest sie, bevor ihr den ersten Write-Workflow baut.
2. Service-User-Konzept: Least Privilege statt Admin-Token
Die bequeme Abkürzung wäre ein Admin-Account als API-User. Macht das nicht. Ein geleaktes Admin-Token bedeutet Vollzugriff auf alle Mitgliederdaten eures Kreises. Der Standard sieht stattdessen dedizierte Service-User vor, jeder mit der minimalen Rolle für genau seinen Zweck. In der Referenz-Installation sind es drei; für den Einstieg reichen die ersten beiden:
| Service-User (Muster) | Zweck | Rechte (minimal) |
|---|---|---|
| Lese-User (KNH: eigener Sync-Account) | Mitglieder, Events, Gruppen lesen für Sync und Anzeige | read-only, z. B. eventList:r |
| Write-User (KNH: eigener Write-Account) | Event-Anmeldungen und Kontakte/Subscriber schreiben | Mitglieder lesen + anmelden, sonst nichts |
| Event-User (KNH: der Event-User) | Events anlegen und ändern (CreateEvent, UpdateEvent) | nur "Veranstaltungen = ändern/+" |
Die Trennung von Lese- und Write-User ist der Kern: Der Sync-User, der ständig im Einsatz ist (Polling alle paar Minuten), kann im schlimmsten Fall nur lesen. Der Write-User kommt nur in den wenigen Workflows zum Einsatz, die tatsächlich nach VO schreiben (bei KNH: Event-Anmeldung, Erstkontakt, Newsletter), und kann selbst dann keine Mitgliederdaten ändern oder löschen.
Drei Betriebsregeln dazu:
- API-User dürfen ausdrücklich NICHT Admin sein. Prüft das nach jeder Rollenänderung in VO nach.
- Ein Gruppen-Eintrag in VO (z. B. Mitgliedschaft in einem Arbeitskreis) ist keine Rechte-Aufwertung. Der KNH-Lese-User steht als reiner Gruppen-Eintrag im "AK Mitglieder", ohne zusätzliche Rechte. Verlasst euch trotzdem nie auf die Annahme, sondern testet die effektiven Rechte per Probe-Request.
- Rechte-Verifikation per Probe: Ob ein User ein Recht wirklich hat, sieht man
am Fehlertyp. Beispiel aus der Referenz:
CreateRegistrationmit dem Write-User liefert bei absichtlich unvollständigen Daten einen Validierungs-Fehler (Recht vorhanden, Eingabe schlecht) statt eines Permission-Fehlers (Recht fehlt). So testet ihr Schreibrechte, ohne echte Datensätze anzulegen.
Credential-Ablage: Token gehören in den Credential-Store der Automation (n8n-Credentials) bzw. in einen verschlüsselten Vault, niemals in Workflow-JSONs, Repos oder Doku. Dieser Standard nennt deshalb ausschließlich Key-Namen und Platzhalter, nie Werte.
3. Die Verhaltensfallen (alle selbst erlitten)
3.1 Stiller Fallback auf anonym
Ein ungültiges Token erzeugt KEINEN Auth-Fehler. Die API antwortet stattdessen,
als wäre niemand angemeldet: leerer Username, anonyme Basisrechte. Sichtbar wird
das nur indirekt, etwa an Meldungen wie
Zugriff verweigert (... (eventList:r eventAnmelden:ab)).
Praktische Regel: Wenn ihr eine Rechte-Fehlermeldung seht, prüft ZUERST Token und Username, nicht die Rolle. Ein Tippfehler im Passwort sieht in VO exakt so aus wie eine fehlende Berechtigung.
3.2 Die Anonym-Rolle kann Events anmelden
In der Referenz-Instanz hat die anonyme Basis-Rolle die Rechte eventList:r
UND eventAnmelden:ab. Das heißt: unauthentifizierte API-Writes
(Event-Anmeldungen) sind möglich. In Kombination mit 3.1 entsteht daraus die
eigentliche Gefahr: Ein Workflow mit kaputtem Token fällt nicht mit einem
Fehler auf, sondern schreibt einfach anonym weiter. Anmeldungen landen dann
ohne den erwarteten User-Kontext in VO, und niemand merkt es.
Konsequenzen für euren Kreis:
- Prüft in eurer VO-Rollenkonfiguration, welche Rechte die Anonym-Rolle hat,
und dreht zu, was ihr nicht braucht. Ob sich
eventAnmeldenfür anonym vollständig entziehen lässt, ist zum Stand dieses Kapitels ungeklärt (offener Punkt der Referenz-Installation); dokumentiert das Ergebnis eurer Prüfung. - Baut in jeden Write-Workflow einen Verifikations-Schritt ein: entweder ein expliziter Login-Check (VerifyLogin/CheckLogin) vor dem Write oder eine Inspektion der Response auf den erwarteten Usernamen. Ein Write-Workflow, der nicht beweisen kann, dass er als der richtige Service-User schreibt, ist nicht fertig.
3.3 Basiskonfiguration gated die Sichtbarkeit: api.getmembers=alle
Ohne den Parameter api.getmembers=alle in der VO-Basis-Konfiguration
(Administration, Basis-Konfiguration, Parameter) liefert GetMembers nur
"freigegebene" Datensätze. Das ist kein theoretisches Problem: In Konstanz-Hegau
kamen so nur 95 von 162 Mitgliedern über die API, und zwar ohne jede
Fehlermeldung. Der Fix kam 2026-05-13 vom VO-Support. Ein Sync auf dieser Basis
hätte ein Drittel des Kreises schlicht nicht gekannt.
Das Events-Pendant ist api.events.alledaten=ja: Erst damit liefert die API
alle Event-Felder unabhängig vom Rollenrecht des abfragenden Users.
Beide Parameter sind NICHT Default. Sie gehören in die Erstkonfiguration jedes
Kreises, der die API nutzt (siehe Checkliste). Weitere Basiskonfig-Parameter,
die das API-Verhalten verändern können (in der Referenz-Instanz nicht gesetzt,
aber bekannt): api.getmembers.datensatz.freigegeben, api.getmembers.einheiten
(Cross-Mandant-Sicht), api.getmembers.felder.freigegeben (Feld-Whitelist),
api.getmembers.filter, api.getevents=alle|sub|up|eigen. Wenn eure API-Antworten
von den Erwartungen abweichen, prüft zuerst diese Parameter.
3.4 Encoding und Transport bei Write-Endpoints
VO behandelt API-Input intern als Latin-1, auch wenn die Doku UTF-8 behauptet (konsistent mit dem ISO-8859-1-CSV-Export). Die Folgen, alle 2026-07-29 in der Referenz-Installation verifiziert:
- JSON-Body mit UTF-8 oder \u-Escapes: Umlaute werden doppelkodiert gespeichert (der "TAeren"-Effekt bei "Türen").
- JSON-Body in Latin-1-Bytes: Parser-Fehler, die API antwortet mit
{"id":0}, denn das serverseitige json_decode braucht valides UTF-8. - Funktionierendes Pattern:
application/x-www-form-urlencodedmit Latin-1-prozentkodierten Werten (z. B.%FCfür ue). - Zusatzfalle: Bei Form-Encoding wird der
Authorization-Header IGNORIERT. Das Token muss dann als&token=in die URL.
Und eine Beruhigung für Event-Writes: sichtbar:0, oeffentlich:0 ist bei frisch
angelegten Events der Normalzustand, kein Fehler. Nicht "reparieren".
3.5 Feld-Gotchas beim Parsen von GetEvents und GetMembers
Die API liefert Felder in Formaten, die jeden naiven Parser brechen (bestätigt 2026-06-26, der Foto-Drop-Trigger fiel genau darüber):
| Feld | Verhalten | Absicherung |
|---|---|---|
zeit | kann Stunde-only sein ("10" statt "10:00") | Regex /^(\d{1,2})(?::(\d{2}))?/, Minuten-Default 0 |
anzahltage | String oder fehlt komplett | Number(...) || 1 |
freieplaetze | String | explizit casten |
ort | kann leer sein | Fallback vorsehen |
datum | verlässlich, immer ISO YYYY-MM-DD | der einzige Anker |
Außerdem: Der max=N-Parameter bei GetMembers wird ignoriert; Begrenzung geht
nur über den filter-Parameter (SQL-where). Zusatzfelder holt ihr über den
felder-Parameter im GetMembers-Call statt über einzelne GetMember-Aufrufe
pro Mitglied. Jeder parsende Workflow muss diese Edge-Cases abdecken, sonst gibt
es stille Ausfälle (silent skips) oder NaN-Werte, die niemand bemerkt.
4. Sicherheits-Baseline für die VO-Basiskonfiguration
Aus den Fallen oben ergibt sich eine kleine, harte Baseline, die jeder Kreis vor dem ersten produktiven API-Einsatz herstellen sollte:
- Anonym-Rechte inventarisieren. Welche Rechte hat die Anonym-Rolle eurer
Instanz? Alles entziehen, was nicht bewusst öffentlich sein soll,
insbesondere Schreibrechte wie
eventAnmelden(soweit VO das zulässt). - Service-User statt Admin. Kein API-Zugang über Admin- oder persönliche Accounts. Lese- und Write-User trennen (Abschnitt 2).
- Starke Passwörter, HTTPS only. Wegen MD5-Token ist das Passwort die gesamte Verteidigung. Rotation über Passwortwechsel einplanen (z. B. bei Vorstandswechsel oder Verdacht).
- Sichtbarkeits-Parameter setzen.
api.getmembers=alleundapi.events.alledaten=jain der Basis-Konfiguration, sonst arbeitet ihr auf unvollständigen Daten, ohne es zu merken. Falls euer Kreis die Mitglieder-Sicht bewusst einschränken will: nutzt dafür die expliziten Parameter (Feld-Whitelist, Filter) statt des impliziten Defaults. - Write-Workflows verifizieren ihre Identität. Login-Check oder Response-Inspektion auf den Usernamen, damit der stille Anonym-Fallback auffliegt.
- Secrets nur im Credential-Store. Token und Passwörter liegen im n8n-Credential-Store oder einem verschlüsselten Vault. In Doku, Repos und Chats stehen nur Key-Namen und Platzhalter.
Checkliste
Mechanisch abhakbar, in dieser Reihenfolge:
- Prod-URL des Kreises identifiziert (Custom-Domain, NICHT
www.vereinonline.org/<KREIS>) - Lese-Service-User angelegt, Rolle minimal (read-only), NICHT Admin
- Write-Service-User angelegt, Rechte nur Mitglieder lesen + anmelden, NICHT Admin
- (Optional) Event-Service-User angelegt, Rechte nur "Veranstaltungen = ändern/+"
- Tokens generiert (
A/<username>/<md5(passwort)>) und ausschließlich im Credential-Store abgelegt api.getmembers=allein der Basis-Konfiguration gesetztapi.events.alledaten=jain der Basis-Konfiguration gesetzt- Vollständigkeit geprüft: Anzahl der Mitglieder aus
GetMembersgegen den Stand in der VO-Oberfläche verglichen - Rechte der Anonym-Rolle inventarisiert und dokumentiert; überzählige Rechte entzogen (soweit möglich)
- Probe mit absichtlich falschem Token gemacht und den Anonym-Fallback einmal selbst gesehen
- Schreibrechte des Write-Users per Probe verifiziert (Validierungs- statt Permission-Fehler)
- Jeder Write-Workflow enthält einen Identitäts-Check (Login-Check oder Response-Inspektion)
- Write-Calls als
application/x-www-form-urlencodedmit Latin-1-Prozentkodierung, Token als&token=in der URL - Parser für
zeit,anzahltage,freieplaetze,ortgegen die Feld-Gotchas abgesichert - Polling-Intervalle festgelegt (Richtwert: nicht unter 5 Minuten)
- Rotations-Prozedur dokumentiert (Passwort wechseln, Token neu erzeugen, Credential aktualisieren)
Referenz KNH
So läuft es bei Konstanz-Hegau konkret (Stand 2026-08-13):
Service-User. Drei User nach dem Muster aus Abschnitt 2: der Lese-User
(read-only, Rolle "WJ-Bot", seit dem Lockdown 2026-05-13), der Write-User
(Anmeldungen und Subscriber) und der Event-User (Event-CRUD). Die Tokens liegen
in den n8n-Credentials VO Header Auth (KNH-Prod) und VO Header Auth (KNH-Write)
sowie für den Event-User als Key WJ_VO_EVENTS_API_TOKEN im SOPS-Vault.
Lesende Nutzung. Drei aktive n8n-Workflows pollen VO read-only: der
Foto-Drop (alle 10 Minuten GetEvents, legt 2 Stunden nach Event-Start einen
Upload-Ordner in Nextcloud an), der Event-Reminder (alle 4 Stunden GetEvents,
erinnert 7 Tage und 24 Stunden vorher) und der Montagspush (montags 08:00
GetMembers mit felder=vorname,nachname,geburtstag,aufnahmemitglied,rollen
für Geburtstage und Jubiläen). Dazu kommt außerhalb von n8n ein
Server-Cronjob für den Events-Sync der Website (täglich 06:00 und 16:00,
VO als synced source statt Live-Backend).
Schreibende Nutzung. Drei Website-Workflows schreiben über den Write-User
nach VO: Event-Anmeldung (GetMembers-Match auf die E-Mail, dann
CreateRegistration als Mitglied per userid oder als Gast; E2E verifiziert
2026-07-03), Erstkontakt (CreateSubscriber in die Interessenten-Gruppe,
Double-Opt-In-Mail verschickt VO selbst) und Newsletter-Anmeldung
(CreateSubscriber in die Newsletter-Gruppe).
Gelebte Lehren. Der api.getmembers=alle-Fix (95 von 162 Mitgliedern
sichtbar, behoben 2026-05-13) und die Encoding-Erkenntnisse vom 2026-07-29
stammen direkt aus diesem Setup. Offener Punkt: ob die Anonym-Rolle das
eventAnmelden-Recht verlieren kann, ist mit dem VO-Support noch zu klären.
Vertiefende Betriebsdoku liegt im wj-Vault unter
08-infrastructure/vereinonline-api-credentials.md (Achtung: enthält
historische Klartext-Notizen, nichts davon in Standard-Dokumente übernehmen).