Custom categories (rights.canDelete=true) have no locale field set by the API and were silently excluded by the locale filter. They now bypass both the locale and taskListType filters so they always appear in get_categories output regardless of the locale parameter. Also: deleted 7 test categories (TEmojiApple, Obst & Gemüse (old), TestKategorie, ProbeKat2, [TEST]emoji=apple, ProbeKat1, TDelMeta) and restored 'Obst & Gemüse' (emoji 🍎) as a clean custom category. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
21 KiB
Family Wall API – Spezifikation
Erarbeitet durch Browser-Traffic-Analyse (April 2026). Es gibt keine offizielle API-Dokumentation.
Base URL
https://api.familywall.com/api
Authentifizierung
Login
POST https://api.familywall.com/api/log2in Content-Type: application/x-www-form-urlencoded
Request-Parameter:
| Parameter | Wert |
|---|---|
identifier |
E-Mail-Adresse |
password |
Passwort |
type |
nicht senden — wird als undefined ignoriert (verifiziert per JS-Analyse) |
clientId |
weglassen |
clientSecret |
weglassen |
generateAutologinToken |
weglassen |
countryCode |
weglassen |
Response (Erfolg):
{ "a00": { "r": { "r": <SessionObject> }, "cn": "log2in" } }
SessionObject enthält u.a. tokenCsrf und webApiUrl.
tokenCsrf ist die Session-ID – identisch zur JSESSIONID im Cookie.
Response (Fehler):
{ "ex": { "ex": <ErrorObject> } }
{ "un": { "un": <ErrorObject> } }
Der Server setzt nach erfolgreichem Login ein Session-Cookie: Set-Cookie: JSESSIONID= (= tokenCsrf)
Folgecalls (nach Login)
Alle API-Calls nach dem Login benötigen:
| Cookie | JSESSIONID=<session-id> |
| Header | Tokencsrf: <session-id> (identisch zur JSESSIONID) |
| Content-Type | application/x-www-form-urlencoded |
Logout
POST https://api.familywall.com/api/log2out Content-Type: application/x-www-form-urlencoded
Keine Parameter. Session wird serverseitig invalidiert.
Session-Strategie
Kein Session-Caching. Jeder MCP-Tool-Call führt folgende Sequenz aus:
POST /api/log2in → Session-ID POST /api/ → Nutzdaten POST /api/log2out → Session invalidieren
Credentials (E-Mail + Passwort) werden einmalig via mcp-familywall setup
im OS Keyring gespeichert (Keys: email, password). Kein Keyring-Eintrag
für session_id.
Bekannte Endpoints
famlistfamily – Kreise abrufen
POST https://api.familywall.com/api/famlistfamily Content-Type: application/x-www-form-urlencoded
Body-Parameter: keine (verifiziert)
Response-Struktur (verifiziert):
a00.r.r[] → Kreise
.metaId → eindeutige Kreis-ID (Format family/<id>)
.name → Kreisname
.family_id → numerische Kreis-ID
.members[] → Mitglieder des Kreises
.accountId → numerische Account-ID
.metaId → Mitglieds-ID (Format familymember/<accountId>_<familyId>)
.firstName → Vorname (Display-Name; bevorzugen gegenüber .name)
.name → E-Mail-Adresse (Family Wall Default wenn kein Anzeigename)
.role → Familienrolle (z.B. "Unknown", "Parent", "Child")
.right → Berechtigung (z.B. "SuperAdmin", "Admin", "Member")
.color → Profilfarbe als Hex-String (z.B. "#FF8086")
.medias[0].pictureUrl → Avatar-URL (generierter Default wenn pictureDefault=true)
.identifiers[] → Kontaktdaten
.type → Typ (z.B. "Email")
.value → Wert (z.B. E-Mail-Adresse)
.familyId → Zugehöriger Kreis (= metaId des Kreises)
.isloggedaccount → "true" wenn das der angemeldete Account ist
.joinDate → Beitrittsdatum (ISO 8601)
.lastLoginDate → Letzter Login (ISO 8601)
.locale → Spracheinstellung (z.B. "de_DE")
.timeZone → Zeitzone (z.B. "Europe/Berlin")
.invitations[] → Offene Einladungen (leer wenn keine)
.coverUri → Cover-Bild URL
taskgettasklists – Listen abrufen
POST https://api.familywall.com/api/taskgettasklists Content-Type: application/x-www-form-urlencoded
Body-Parameter: keine
Response-Struktur: zu verifizieren beim ersten echten Call
accgetallfamily – Listen + Tasks abrufen
POST https://api.familywall.com/api/accgetallfamily Content-Type: application/x-www-form-urlencoded
Body-Parameter:
| Parameter | Wert |
|---|---|
a01call |
"taskcategorysync" |
a02call |
"tasksync" |
Hinweis: a03call=tasklistsync ist kein gültiger Endpoint — API antwortet mit
"The call tasklistsync is not registered". Nicht verwenden.
partnerScope, a03id, withStateBean werden weggelassen.
Response-Struktur (verifiziert):
a00 → famlistfamily-Daten (Kreise inkl. members[]) – Nebeneffekt
a01.r.r.updatedCreated[] → taskcategorysync (Kategorien/Abteilungen pro Liste)
.metaId → Kategorie-ID (Format taskCategory/<familyId>_<sysId>)
.name → Kategoriename (sprachabhängig, z.B. "Beverages")
.emoji → Emoji-Symbol der Kategorie
.systemCategoryId → numerische System-ID (sprach-unabhängig)
.taskListType → Listentyp der Kategorie (z.B. "SHOPPING_LIST")
**Wichtig:** Alle 171 Kategorien sind SHOPPING_LIST —
es gibt keine TODO-Kategorien in der API
.sortingIndexByTaskList → dict: Listen-ID → Sortierposition
**Achtung:** enthält ALLE Listen-IDs unabhängig vom Typ
→ NICHT für Typ-Filterung verwenden!
Stattdessen: taskListType der Kategorie mit
taskListType der Liste (aus taskgettasklists) vergleichen
.locale → Sprache des Namens (z.B. "de", "en", "ru", "fr", "es",
"it", "nl", "pt", "sv", "ko", "ja")
Jede Sprache = eigener Eintrag mit eigenem metaId/systemCategoryId
**Wichtig:** Custom-Kategorien (rights.canDelete='true') haben
kein locale-Feld gesetzt — sie werden sprachunabhängig
zurückgegeben und dürfen nie über locale gefiltert werden.
.hiddenByTaskList → Liste von Listen-IDs, in denen die Kat. versteckt ist
a02.r.r.updatedCreated[] → tasksync (Tasks)
.metaId → eindeutige Task-ID
.taskId → identisch zu metaId (zweiter Alias)
.text → Aufgabentext
.description → optionale Beschreibung
.taskListId → Zugehörigkeit zur Liste
.complete → "true" / "false" (String, nicht Boolean!)
.categories[] → Listen-Level-Systemkategorie (z.B. SYS-CAT-SHOPPINGLIST);
NICHT die spezifische Task-Kategorie — immer identisch
für alle Tasks einer Liste
.system → "true" (immer System-Kategorie)
.name → Listen-Systemkategorien (z.B. "SYS-CAT-SHOPPINGLIST", "SYS-CAT-TODOS")
.taskCategoryId → spezifische Task-Kategorie (verifiziert): metaId-Format
(z.B. "taskCategory/23431854_200"), null wenn nicht gesetzt
.assignee / .assigneeIds → zugewiesene Mitglieder
.reminder → Erinnerungsdatum (ISO 8601, optional)
.recurrency → Wiederholungsregel (optional)
.sortingIndex → Anzeigereihenfolge
Kategorie-Zuweisung bei taskcreate2 / taskupdate2 (verifiziert):
| Parameter | Pflicht | Wert |
|---|---|---|
taskCategoryId |
nein | Kategorie-MetaId aus get_categories (z.B. taskCategory/23431854_200) |
Hinweise:
- Wert muss das vollständige metaId-Format
taskCategory/<familyId>_<systemCategoryId>sein. Nur der numerischesystemCategoryId-Teil (z.B.200) führt zu API-Fehler"cannot find task category id=200". - Das
categories[]-Feld in der Response zeigt immerSYS-CAT-SHOPPINGLIST(Listen-Level-Systemkategorie, unabhängig vom gesetztentaskCategoryId). Die tatsächliche Task-Kategorie ist im FeldtaskCategoryIdder Task gespeichert. - Nur für Einkaufslisten (
taskListType=SHOPPING_LIST) relevant; TODO-Listen haben keine Kategorien.
Systembezeichnungen für Listen-Namen
Bekannte Systembezeichnungen werden deutsch übersetzt:
| Systembezeichnung | Deutsch |
|---|---|
SYS-CAT-SHOPPINGLIST |
Einkaufsliste |
Unbekannte Bezeichnungen werden unverändert zurückgegeben. Mapping-Tabelle bei Bedarf erweitern.
wallget – Aktivitäten (Wall) abrufen
POST https://api.familywall.com/api/wallget Content-Type: application/x-www-form-urlencoded
Body-Parameter:
| Parameter | Wert |
|---|---|
nb |
Anzahl Einträge (z.B. "20") |
date |
optional, für Paginierung (Datum des letzten Eintrags) |
accountId |
optional |
type |
optional |
nested |
optional |
masterNested |
optional |
sortBy |
optional |
Response-Struktur (verifiziert):
a00.r.r[]
.metaId → ID der Aktivität (= wallMessageId)
.refType → Aktivitätstyp (z.B. STATUS, FAMILY_CREATED)
.text → Text (optional, fehlt bei System-Events)
.creationDate → Datum (ISO 8601)
.accountId → Autor-ID
Response-Struktur: zu verifizieren beim ersten echten Call
wallactivityget – Einzelne Aktivität abrufen
POST https://api.familywall.com/api/wallactivityget Content-Type: application/x-www-form-urlencoded
Body-Parameter:
| Parameter | Wert |
|---|---|
accountId |
optional |
masterNested |
optional |
Response-Struktur: zu verifizieren beim ersten echten Call (Endpoint noch nicht implementiert — für spätere Versionen)
Debug-Logging
Wenn die Umgebungsvariable FW_DEBUG=1 gesetzt ist, loggt fw_client.py
vollständige Request-Bodies und Responses nach stderr. Dient zur Verifikation
offener Punkte (z.B. type-Parameter beim Login, Kreis-Felder in Response).
Wichtig: Keine Secrets in Debug-Ausgaben (Passwort maskieren).
taskcreate2 – Task erstellen
POST https://api.familywall.com/api/taskcreate2 Content-Type: application/x-www-form-urlencoded
Body-Parameter (verifiziert):
| Parameter | Pflicht | Wert |
|---|---|---|
taskListId |
ja | Listen-ID aus get_lists (z.B. taskList/123_456) |
text |
ja | Aufgabentitel |
description |
nein | Optionale Beschreibung |
taskCategoryId |
nein | Kategorie-MetaId aus get_categories (z.B. taskCategory/23431854_200) |
Response-Struktur (verifiziert):
a00.r.r → vollständiges Task-Objekt der neu erstellten Task
.metaId → eindeutige Task-ID (z.B. "task/23431854_726362809")
.taskListId → Listen-ID
.text → Titel
.complete → "false" (immer, direkt nach Erstellung)
taskupdate2 – Task aktualisieren
POST https://api.familywall.com/api/taskupdate2 Content-Type: application/x-www-form-urlencoded
Body-Parameter (verifiziert):
| Parameter | Pflicht | Wert |
|---|---|---|
metaId |
ja | Task-ID aus get_tasks |
text |
nein | Neuer Titel (mindestens eines der optionalen Felder erforderlich) |
description |
nein | Neue Beschreibung |
taskCategoryId |
nein | Kategorie-MetaId aus get_categories (z.B. taskCategory/23431854_200) |
Hinweis: taskListId ist nicht erforderlich (verifiziert – Update ohne taskListId funktioniert).
Response-Struktur: kein spezifischer Rückgabewert – Erfolg = kein ex/un-Key auf Top-Level.
taskmark – Task als erledigt/offen markieren
POST https://api.familywall.com/api/taskmark Content-Type: application/x-www-form-urlencoded
Body-Parameter (verifiziert):
| Parameter | Pflicht | Wert |
|---|---|---|
taskId |
ja | Task-ID aus get_tasks (WICHTIG: taskId, nicht metaId!) |
complete |
ja | "true" oder "false" (String, nicht Boolean!) |
Achtung: Der Endpoint heißt intern taskId, nicht metaId.
Falsche Parameter (metaId, id, taskMetaId) werden serverseitig ignoriert –
die API antwortet dann mit einem Fehler in a00.un.un (nicht Top-Level!),
der vom Standard-Error-Check im fw_client übersehen wird.
Response-Struktur (verifiziert):
a00.r.r → vollständiges Task-Objekt mit aktuellem Stand (inkl. lastAction: "MARK_COMPLETED")
metadelete – Objekt löschen
POST https://api.familywall.com/api/metadelete Content-Type: application/x-www-form-urlencoded
Body-Parameter (verifiziert):
| Parameter | Pflicht | Wert |
|---|---|---|
id |
ja | Task-ID aus get_tasks (WICHTIG: id, nicht metaId!) |
Hinweis: metadelete ist ein generischer Lösch-Endpoint für beliebige Objekte (Tasks, etc.).
Entsprechend vorsichtig verwenden.
Response-Struktur (verifiziert):
a00.r.r → "true" (String)
Fehlerverhalten: Bei falschem Parameter-Namen (metaId, taskId etc.) antwortet die API
mit {"a00": {"un": {"un": {"message": "missing value in: id"}}}} auf Top-Level ohne un-Key
→ wird vom fw_client fälschlich als Erfolg interpretiert. Daher ist der korrekte Parameter-Name
kritisch.
taskcategoryput – Kategorie erstellen
POST https://api.familywall.com/api/taskcategoryput Content-Type: application/x-www-form-urlencoded
Body-Parameter (verifiziert via FW_DEBUG=1):
| Parameter | Pflicht | Wert |
|---|---|---|
name |
ja | Kategorie-Name (beliebiger String) |
emoji |
nein | Icon: Unicode-Emoji-Zeichen (z.B. 🌿) oder beliebiger String-Code (z.B. "FOOD") — wird as-is gespeichert |
Hinweise:
- Die neue Kategorie wird allen Listen der Familie zugeordnet — es gibt keine per-Liste-Einschränkung.
- Benutzerdefinierte Kategorien haben
systemCategoryId=nullundrights.canDelete='true'. - System-Kategorien haben
rights.canDelete=null— API erlaubt Löschen, aberdelete_categoryTool verweigert es.
Response-Struktur (verifiziert):
a00.r.r → vollständiges Kategorie-Objekt
.metaId → neue Kategorie-ID (z.B. "taskCategory/23431854_4956637")
.name → Kategorie-Name
.taskListType → "SHOPPING_LIST" (automatisch gesetzt)
.familyId → Familien-ID
.accountId → Account-ID des Erstellers
.rights.canDelete → "true" (custom Kategorien)
.rights.canUpdate → "true" (custom Kategorien)
.emoji → gespeicherter Icon-Wert (falls übergeben)
Fehlerverhalten: Ohne name-Parameter:
{"a00": {"un": {"un": {"FiZClassId": "502", "message": "cat without a name ..."}}}}
taskcategorydelete – Kategorie löschen
POST https://api.familywall.com/api/taskcategorydelete Content-Type: application/x-www-form-urlencoded
Body-Parameter (verifiziert via FW_DEBUG=1):
| Parameter | Pflicht | Wert |
|---|---|---|
id |
ja | Kategorie-MetaId aus get_categories (WICHTIG: id, nicht metaId!) |
Achtung: Falscher Parameter-Name metaId führt zu:
{"a00": {"un": {"un": {"FiZClassId": "502", "message": "In request, missing value in : id"}}}}
Response-Struktur (verifiziert):
a00.r.r → "true" (String)
Wichtig – System-Kategorien: Die API erlaubt technisch das Löschen von System-Kategorien
(taskCategory/<familyId>_200 etc.), entfernt sie aber nur aus der Familie — nicht global.
Das delete_category-MCP-Tool verweigert dies (Schutz via rights.canDelete-Check).
Erkennung: custom Kategorien haben rights.canDelete='true'; System-Kategorien haben rights.canDelete=null.
wallmood – Wall-Post liken
POST https://api.familywall.com/api/wallmood Content-Type: application/x-www-form-urlencoded
Body-Parameter (verifiziert via FW_DEBUG=1):
| Parameter | Pflicht | Wert |
|---|---|---|
wall_message_id |
ja | Post-ID aus get_activities (z.B. wall/23431854_31119189) |
moodType |
ja | "STAR" (einziger bekannter Wert — entspricht dem Like-Button in der App) |
Verhalten (verifiziert):
wallmoodmitmoodType: "STAR"ist eine idempotente SET-Operation — kein Toggle!- Mehrfaches Aufrufen mit denselben Parametern hinterlässt denselben Zustand
moodType: "LIKE"wurde serverseitig als"STAR"gespeichert → korrekter Wert ist"STAR"- Nur für Post-Typ
STATUSwirksam;FAMILY_CREATEDund vermutlich System-Posts ignorieren den Call
Unlike – nicht implementierbar (Stand: April 2026):
Ausgiebig getestete Ansätze, die alle fehlschlugen:
| Ansatz | Ergebnis |
|---|---|
moodType: "NONE" / "REMOVE" / "DELETE" / "" |
moodMap unverändert |
moodType ganz weglassen |
moodMap unverändert |
moodStarShortcut: "false" als Parameter |
moodMap unverändert |
Alternative Endpoints: wallmooddelete, wallmoodremove, wallmoodelete, wallunmood, wallcommentdelete, wallmoodstar, wallstar, wallreact, wallreactdelete |
alle: "The call X is not registered" (502) |
metadelete auf Mood-Comment-ID |
löscht den Comment, aber moodStarShortcut bleibt gesetzt |
Die Web-App nutzt einen Service Worker, der Requests abfängt — der echte Unlike-Payload ist dadurch nicht per Browser-DevTools inspizierbar. Unlike bleibt bis zur weiteren Analyse nicht unterstützt.
Response-Struktur (verifiziert):
a00.r.r → vollständiges Wall-Message-Objekt
.metaId → Post-ID (= wallMessageId)
.wallMessageId → Post-ID (identisch zu metaId)
.refType → Aktivitätstyp (z.B. "STATUS")
.refAction → Letzte Aktion (z.B. "MOOD_STAR")
.text → Post-Text
.postAccountId → Account-ID des Post-Autors
.accountId → Account-ID (identisch)
.moodMap → dict: accountId → ["STAR"] wenn geliked
.moodStarShortcut → "true" wenn Like-Shortcut aktiv
.comments[] → Liste von Kommentaren/Moods
.commentId → Kommentar-ID (Format wallComment/...)
.accountId → Account-ID des Kommentators
.mood → Mood-Typ (z.B. "STAR")
.text → Kommentartext (falls vorhanden)
.creationDate → Erstelldatum (ISO 8601)
.creationDate → Erstelldatum des Posts (ISO 8601)
.modifDate → Letztes Änderungsdatum (ISO 8601)
.familyId → Kreis-ID (Format family/...)
.rights.canUpdate → "true"/"false"
.rights.canDelete → "true"/"false"
Like-Zustand bestimmen (zwei Indikatoren, beide auswerten):
| Feld | Typ | Bedeutung |
|---|---|---|
moodStarShortcut |
"true" / "false" |
Primär: direktes User-Like-Flag für den anfragenden Account |
moodMap[accountId] |
["STAR"] |
Sekundär: accountId → Mood-Liste; enthält "STAR" wenn geliked |
Beide Indikatoren können den Like-Zustand korrekt abbilden — je nach API-internem Speicherpfad ist nur einer gesetzt. Immer beide prüfen.
Silent-Fail-Szenarien (API antwortet 200, aber Like wird nicht gesetzt):
- Self-Like-Restriction: Eigener Post kann nicht geliked werden
(verifiziert: Account 23431898 kann Post
wall/23431854_31119189nicht liken, obwohl API regulär antwortet —modifDatebleibt eingefroren) - Unsupported Post-Typ:
FAMILY_CREATED-Posts ignorieren wallmood-Calls - Rate-Limit: Nach vielen Calls kann die API Still-Fails zurückgeben
Erkennungsmerkmal für Silent-Fail: modifDate im Response identisch zum Vorherigen
AND moodStarShortcut: false AND moodMap: {}.
Noch zu verifizieren
Exakter Wert für→ nicht senden (verifiziert per JS-Analyse)type-Parameter beim LoginResponse-Struktur von→ a00.r.r[], metaId + name (verifiziert)famlistfamily(Kreise)Ob→ nein, kein gültiger Endpoint (verifiziert)a03call=tasklistsyncbenötigt wird- Listen-IDs aus
a01.r.r.updatedCreated[].sortingIndexByTaskList-Keys (verifiziert) - Listen-Namen und Zähler (remainingTaskNumber, totalTaskNumber) → noch unbekannt
- Kreis-Zuordnung in
accgetallfamily-Response → noch offen Ob→ nein (verifiziert)partnerScope/withStateBeanbenötigt werden- Session-Lebensdauer (irrelevant da kein Caching)
→taskcreate2: Response-Struktura00.r.r= vollständiges Task-Objekt (verifiziert)→ nein, nicht erforderlich (verifiziert)taskupdate2: obtaskListIdPflichtfeld ist→taskmark: korrekter Parameter-NametaskId(nichtmetaId!) (verifiziert)→metadelete: korrekter Parameter-Name + Response-Strukturid, Response"true"(verifiziert)→wallmood: Parameter-NamewallIdwall_message_id(verifiziert via API-Fehlermeldung)→ verifiziert: idempotentes SET mitwallmood:moodType-Werte, Toggle vs. explizit, Response-Struktur"STAR", kein Toggle (siehe oben)wallmoodUnlike: Mechanismus unbekannt — Service Worker verhindert Browser-Inspektion; alle getesteten Ansätze fehlgeschlagen (siehe oben)→taskcreate2/taskupdate2: Kategorie-Paramter-NametaskCategoryId, Wert = vollständige metaId (verifiziert)→taskcategoryput: Body-Parameter, Response-Strukturname(Pflicht),emoji(optional), Response = neues Kategorie-Objekt (verifiziert)→taskcategorydelete: Body-Parameterid(nichtmetaId!), Response ="true"(verifiziert)