4a3fe6be87
get_lists now includes emoji and color fields per list entry.
create_list response also returns emoji and color from the API.
Field name verification (FW_DEBUG=1, 2026-04-16):
- emoji: API returns "" when unset -> normalised to null
- color: API omits key when unset -> normalised to null
- Both fields present in taskgettasklists and taskcreatelist responses
SPEC.md: taskgettasklists documented with full response structure
and emoji/color normalisation notes.
taskcreatelist response updated with emoji + color fields.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
396 lines
12 KiB
Markdown
396 lines
12 KiB
Markdown
# Family Wall API – Spezifikation
|
||
|
||
Erarbeitet durch Browser-Traffic-Analyse und React-Fiber-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` | `"email"` (verifiziert) |
|
||
|
||
**Response (Erfolg):**
|
||
|
||
```json
|
||
{ "r": { "r": <SessionObject> } }
|
||
```
|
||
|
||
**Response (Fehler):**
|
||
|
||
```json
|
||
{ "ex": { "ex": <ErrorObject> } }
|
||
{ "un": { "un": <ErrorObject> } }
|
||
```
|
||
|
||
Der Server setzt nach erfolgreichem Login ein Session-Cookie:
|
||
`Set-Cookie: JSESSIONID=<session-id>`
|
||
|
||
### Folgecalls (nach Login)
|
||
|
||
| | |
|
||
|---|---|
|
||
| **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
|
||
|
||
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/<endpoint> → Nutzdaten (ggf. mehrere Calls in einer Session)
|
||
POST /api/log2out → Session invalidieren
|
||
```
|
||
|
||
Credentials (E-Mail + Passwort) werden einmalig via `mcp-familywall setup`
|
||
im OS Keyring gespeichert (Keys: `email`, `password`).
|
||
|
||
## Fehlerbehandlung
|
||
|
||
### Silent-Fail Warnung
|
||
Die API gibt Fehler manchmal NICHT auf Top-Level zurück, sondern eingebettet:
|
||
|
||
```json
|
||
{"a00": {"un": {"un": {"message": "missing value in: taskId"}}}}
|
||
```
|
||
|
||
`fw_client.py` prüft beide Ebenen (`a00.un.un` und Top-Level `ex`/`un`)
|
||
und wirft `FamilyWallError`. Nie eine Response als Erfolg werten ohne
|
||
beide Fehlerebenen zu prüfen.
|
||
|
||
### Sentinel-Wert `$empty`
|
||
Das FiZ-Server-Framework nutzt `$empty` als Sentinel-String um optionale
|
||
Felder zu löschen. Alle anderen Werte (`""`, `null`, `"null"`, `"0"`,
|
||
`"-1"`, `"remove"`, `"clear"`, Epoch-Timestamps) werden vom Server mit
|
||
`"is not a valid Date"` abgelehnt.
|
||
|
||
**Aktuell genutzt für:**
|
||
- `dueDate=$empty` → löscht Fälligkeitsdatum in `taskupdate2`
|
||
|
||
**Gefunden durch:** React-Fiber-Analyse des nativen `datetime-local`-Inputs –
|
||
nach Klick auf "Löschen" im Custom-Datepicker wird der Input-Wert auf
|
||
`"$empty"` gesetzt, was beim Speichern an die API gesendet wird.
|
||
|
||
## Bekannte Endpoints
|
||
|
||
### `famlistfamily` – Kreise + Mitglieder abrufen
|
||
POST https://api.familywall.com/api/famlistfamily
|
||
|
||
**Body-Parameter:** keine
|
||
|
||
**Response-Struktur:**
|
||
```
|
||
a00.r.r[] → Kreise
|
||
.metaId → Kreis-ID (z.B. "family/23431854")
|
||
.name → Kreis-Name
|
||
.members[] → Mitglieder des Kreises
|
||
.accountId → numerische User-ID
|
||
.firstName → Anzeigename (bevorzugen)
|
||
.name → E-Mail als Fallback
|
||
.role → Familienrolle (Parent/Child/Unknown)
|
||
.right → Berechtigung (SuperAdmin etc.)
|
||
.color → Profilfarbe (#RRGGBB)
|
||
.medias[0].pictureUrl → Avatar-URL
|
||
.identifiers[type=Email].value → E-Mail-Adresse
|
||
```
|
||
|
||
### `accgetallfamily` – Listen, Tasks, Kategorien abrufen
|
||
POST https://api.familywall.com/api/accgetallfamily
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Wert |
|
||
|---|---|
|
||
| `a01call` | `"taskcategorysync"` |
|
||
| `a02call` | `"tasksync"` |
|
||
|
||
**Response-Struktur:**
|
||
```
|
||
a00.r.r[] → Kategorien (taskcategorysync)
|
||
.metaId → Kategorie-ID
|
||
.name → Kategoriename (Systembezeichnung)
|
||
.taskListType → SHOPPING_LIST oder TODOS
|
||
.sortingIndexByTaskList → Sortierreihenfolge pro Liste
|
||
.rights.canDelete → "true" = custom, null = System
|
||
.locale → Sprachcode (de/en/fr/...), fehlt bei custom
|
||
|
||
a02.r.r.updatedCreated[] → Tasks (tasksync)
|
||
.metaId → Task-ID
|
||
.text → Aufgabentext
|
||
.description → optionale Beschreibung
|
||
.taskListId → Listen-ID
|
||
.complete → "true" / "false" (String!)
|
||
.taskCategoryId → Kategorie-ID (optional)
|
||
.dueDate → Fälligkeitsdatum (ISO 8601, optional)
|
||
.assignee[] → Liste von Member-IDs (optional)
|
||
.assigneeIds[] → alternativ zu assignee[]
|
||
```
|
||
|
||
### `wallget` – Wall-Aktivitäten abrufen
|
||
POST https://api.familywall.com/api/wallget
|
||
|
||
**Response-Struktur:**
|
||
```
|
||
a00.r.r[]
|
||
.metaId → Post-ID (z.B. "wall/23431854_31119189")
|
||
.type → STATUS, FAMILY_CREATED, etc.
|
||
.text → Post-Text
|
||
.modifDate → Timestamp (ISO 8601)
|
||
.creator.accountId → Author-ID
|
||
.moodMap → {"<accountId>": ["STAR"]} für Likes
|
||
.moodStarShortcut → true wenn geliked
|
||
.comments[] → Kommentare
|
||
```
|
||
|
||
### `taskcreate2` – Task erstellen
|
||
POST https://api.familywall.com/api/taskcreate2
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Pflicht | Wert |
|
||
|---|---|---|
|
||
| `taskListId` | ja | Listen-metaId |
|
||
| `text` | ja | Aufgabentext |
|
||
| `description` | nein | Beschreibung |
|
||
| `taskCategoryId` | nein | Kategorie-metaId (vollständig, z.B. `taskCategory/23431854_200`) |
|
||
| `dueDate` | nein | ISO 8601 (z.B. `2026-04-30T18:00:00`) |
|
||
| `assignee` | nein | Member-accountId, mehrfach sendbar für mehrere Zuweisungen |
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → vollständiges Task-Objekt
|
||
.metaId → neue Task-ID
|
||
```
|
||
|
||
### `taskupdate2` – Task aktualisieren
|
||
POST https://api.familywall.com/api/taskupdate2
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Pflicht | Wert |
|
||
|---|---|---|
|
||
| `metaId` | ja | Task-metaId |
|
||
| `text` | nein | neuer Titel |
|
||
| `description` | nein | neue Beschreibung |
|
||
| `taskCategoryId` | nein | neue Kategorie-metaId |
|
||
| `dueDate` | nein | ISO 8601 oder `$empty` zum Löschen |
|
||
| `assignee` | nein | Member-accountId (mehrfach sendbar), `""` zum Entfernen aller |
|
||
| `taskListId` | nein | neue Listen-metaId (verschiebt Task) |
|
||
|
||
**Hinweis:** `taskListId` ist NICHT Pflicht beim Update.
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → vollständiges Task-Objekt
|
||
```
|
||
|
||
### `taskmark` – Task abhaken/wiedereröffnen
|
||
POST https://api.familywall.com/api/taskmark
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Wert |
|
||
|---|---|
|
||
| `taskId` | Task-metaId ⚠️ nicht `metaId`! |
|
||
| `complete` | `"true"` oder `"false"` (String!) |
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → Task-Objekt mit lastAction: "MARK_COMPLETED"
|
||
```
|
||
|
||
### `metadelete` – Task löschen
|
||
POST https://api.familywall.com/api/metadelete
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Wert |
|
||
|---|---|
|
||
| `id` | Task-metaId ⚠️ nicht `metaId`! |
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → "true" (String)
|
||
```
|
||
|
||
### `wallmood` – Post liken
|
||
POST https://api.familywall.com/api/wallmood
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Wert |
|
||
|---|---|
|
||
| `wall_message_id` | Post-metaId ⚠️ nicht `wallId` oder `id`! |
|
||
| `moodType` | `"STAR"` für Like |
|
||
|
||
**Bekannte Einschränkungen:**
|
||
- Unlike: Endpoint/Parameter unbekannt (Service Worker verschlüsselt Request-Body)
|
||
- Self-Like: API antwortet 200, macht aber serverseitig nichts
|
||
- `moodType="NONE"` und andere Werte haben keine Wirkung
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → Wall-Objekt mit moodMap, refAction: "MOOD_STAR"
|
||
```
|
||
|
||
### `taskcategoryput` – Kategorie erstellen/aktualisieren
|
||
POST https://api.familywall.com/api/taskcategoryput
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Pflicht | Wert |
|
||
|---|---|---|
|
||
| `name` | ja | Kategoriename |
|
||
| `emoji` | nein | Unicode-Emoji oder beliebiger String |
|
||
|
||
**Hinweis:** Kategorien sind family-wide – `listId` hat keine Wirkung.
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → Kategorie-Objekt mit metaId
|
||
```
|
||
|
||
### `taskcategorydelete` – Kategorie löschen
|
||
POST https://api.familywall.com/api/taskcategorydelete
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Wert |
|
||
|---|---|
|
||
| `id` | Kategorie-metaId ⚠️ nicht `metaId`! |
|
||
|
||
**Hinweis:** System-Kategorien (`rights.canDelete=null`) können technisch
|
||
gelöscht werden, sind dann aber dauerhaft weg und nicht wiederherstellbar.
|
||
MCP-Server schützt dagegen durch Check auf `rights.canDelete`.
|
||
|
||
### `taskcreatelist` – Liste erstellen
|
||
POST https://api.familywall.com/api/taskcreatelist
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Pflicht | Wert |
|
||
|---|---|---|
|
||
| `name` | ja | Listen-Name (max 200 Zeichen) |
|
||
| `taskListType` | ja | `"SHOPPING_LIST"` oder `"TODOS"` |
|
||
| `sharedToAll` | nein | `"true"` / `"false"` (default: `"true"`) |
|
||
| `color` | nein | Hex-Farbwert z.B. `"#4784EC"` |
|
||
| `emoji` | nein | Unicode-Emoji z.B. `"🛒"` |
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → vollständiges Listen-Objekt
|
||
.metaId → neue Listen-ID (z.B. "taskList/23431854_29759623")
|
||
.name → Listen-Name
|
||
.taskListType → SHOPPING_LIST oder TODOS
|
||
.sharedToAll → "true" / "false"
|
||
.emoji → Unicode-Emoji (fehlt wenn nicht gesetzt)
|
||
.color → Hex-Farbwert z.B. "#E53935" (fehlt wenn nicht gesetzt)
|
||
.rights.canDelete → "true" (user-created lists)
|
||
```
|
||
|
||
**Verifiziert am:** 2026-04-16 via FW_DEBUG=1
|
||
|
||
### `taskdeletelist` – Liste löschen
|
||
POST https://api.familywall.com/api/taskdeletelist
|
||
|
||
**Body-Parameter:**
|
||
|
||
| Parameter | Wert |
|
||
|---|---|
|
||
| `id` | Listen-metaId ⚠️ nicht `listId` oder `taskListId`! |
|
||
|
||
**Response:**
|
||
```
|
||
a00.r.r → "true" (String)
|
||
```
|
||
|
||
**Hinweis:** Löscht die Liste und alle enthaltenen Tasks unwiderruflich.
|
||
System-Listen (`rights.canDelete` fehlt oder `null`) sind nicht löschbar.
|
||
MCP-Server prüft dies vor dem Löschen via `taskgettasklists`.
|
||
|
||
**Verifiziert am:** 2026-04-16 via FW_DEBUG=1
|
||
|
||
### `taskgettasklists` – Listen abrufen
|
||
POST https://api.familywall.com/api/taskgettasklists
|
||
|
||
**Body-Parameter:** keine
|
||
|
||
**Response-Struktur:**
|
||
```
|
||
a00.r.r[] → Liste aller Task-Listen
|
||
.metaId → Listen-ID (z.B. "taskList/23431854_29740942")
|
||
.name → Systembezeichnung oder Benutzer-Name
|
||
.taskListType → SHOPPING_LIST oder TODOS
|
||
.emoji → Unicode-Emoji oder "" (leerer String = kein Emoji)
|
||
.color → Hex-Farbwert z.B. "#E53935" (fehlt wenn nicht gesetzt)
|
||
.remainingTaskNumber → offene Tasks (String)
|
||
.totalTaskNumber → Gesamt-Tasks (String)
|
||
.sharedToAll → "true" / "false"
|
||
.sharedMemberIds[] → Member-accountIds
|
||
.rights.canDelete → "true" = löschbar, fehlt/leer = Systemliste
|
||
.systemId → vorhanden nur bei Systemlisten (z.B. "-10", "-11")
|
||
```
|
||
|
||
**Hinweis emoji/color:**
|
||
- `emoji`: Systemlisten liefern `""`, user-created Listen liefern den Emoji-String
|
||
oder `""` wenn kein Emoji gesetzt. Normalisierung: `""` → `null` im MCP-Server.
|
||
- `color`: Fehlt komplett wenn nicht gesetzt (nicht `null` oder `""`).
|
||
Normalisierung: fehlendes Feld → `null` im MCP-Server.
|
||
|
||
**Verifiziert am:** 2026-04-16 via FW_DEBUG=1
|
||
|
||
## Systembezeichnungen für Listen-Namen
|
||
|
||
| Systembezeichnung | Deutsch |
|
||
|---|---|
|
||
| `SYS-CAT-SHOPPINGLIST` | `Einkaufsliste` |
|
||
| `SYS-CAT-TODOLIST` | `Aufgaben` |
|
||
|
||
## Debug-Logging
|
||
|
||
Wenn die Umgebungsvariable `FW_DEBUG=1` gesetzt ist, loggt `fw_client.py`
|
||
vollständige Request-Bodies und Responses nach stderr.
|
||
|
||
**Wichtig:** Keine Secrets in Debug-Ausgaben (Passwort maskieren).
|
||
|
||
**Wann FW_DEBUG=1 nutzen:**
|
||
- Neue Endpoints verifizieren
|
||
- Parameter-Namen unbekannt
|
||
- Silent-Fail debuggen
|
||
- Service Worker blockiert Browser-DevTools
|
||
|
||
## Service Worker
|
||
|
||
Die Family Wall Web-App registriert einen Service Worker der bestimmte
|
||
HTTP-Requests abfängt und modifiziert bevor sie das Netzwerk erreichen.
|
||
Betroffen sind u.a. Unlike-Calls und möglicherweise andere schreibende
|
||
Operationen.
|
||
|
||
**Folge:** Browser-DevTools Network-Tab und JS-Interceptoren (XHR/Fetch)
|
||
zeigen nicht den echten Request-Body für diese Calls.
|
||
**Lösung:** `FW_DEBUG=1` auf MCP-Server-Seite zeigt was tatsächlich gesendet wird.
|
||
|
||
## Offene Punkte
|
||
|
||
- Unlike-Endpoint (Service Worker blockiert Analyse)
|
||
- Erinnerungen (reminder) – nur Premium-Account
|
||
- Wiederholungen (repeat) – nur Premium-Account
|
||
- Sortierung von Kategorien via API
|