Ich investiere über Scalable Capital und wollte meine Portfoliodaten in einem eigenen Dashboard zusammenführen. Eine öffentliche API gibt es nicht, also habe ich mir einen lokalen Proxy gebaut.
Das Login-Problem
Das erste Hindernis war die Authentifizierung. Credentials hardcoden kam nicht in Frage, und das Login-Formular zu scrapen wäre beim nächsten Frontend-Update gebrochen.
Die Lösung: Puppeteer öffnet ein echtes Chromium-Fenster, ich logge mich selbst ein inklusive 2FA, und das Skript wartet, bis die SPA vollständig geladen ist. Aus dem authentifizierten Browser-State extrahiert es Session-Cookies, Portfolio-ID und weitere IDs, die für die späteren API-Calls nötig sind.
Die Session wird auf Disk gespeichert und beim nächsten Server-Start wiederhergestellt, ein Neustart erzwingt also kein erneutes Login. Antwortet ein Request mit 401 oder 403, wird der Login-Flow automatisch neu gestartet und der Request einmalig wiederholt.
Die eigentliche API
Die Scalable Capital App kommuniziert intern mit einem privaten GraphQL-Endpunkt. Echtzeit-Daten laufen über einen WebSocket mit dem graphql-transport-ws-Protokoll.
Das Protokoll habe ich manuell implementiert statt eine fertige Client-Library zu nutzen, damit die Reconnect- und Subscription-Logik transparent bleibt.
WebSocket-Singleton und SSE-Bridge
Eine einzelne WebSocket-Verbindung zum Upstream wird von allen verbundenen SSE-Clients geteilt. Die Verbindung wird beim ersten Client aufgebaut und beim letzten wieder abgebaut.
[SSE-Client 1] ──┐
[SSE-Client 2] ──┤── SubscriptionManager ── einzelne WS-Sub ── Upstream WS
[SSE-Client N] ──┘
Für Kurs-Streams verwaltet der QuoteManager die Vereinigungsmenge aller angeforderten ISINs. Kommt ein neuer Client mit anderen ISINs dazu, wird die Upstream-Subscription aktualisiert und jeder eingehende Tick vor der Weiterleitung pro Client gefiltert.
REST-Clients bekommen das transparent: GET /portfolio gibt einen gecacheten WebSocket-Tick zurück, wenn er frisch genug ist, und wartet sonst kurz auf die nächste Nachricht.
Endpunkte
Auth
POST /auth/login,GET /auth/status,DELETE /auth/logout
Portfolio
GET /portfolio– aktuelle BewertungGET /portfolio/inventory– Positionen und SparpläneGET /portfolio/cash– Kaufkraft und AuszahlungskraftGET /portfolio/timeseries– zeitgewichtete Rendite- weitere:
/watchlist,/interest-rates,/pending-orders
Wertpapiere
GET /securities/:isin– Details mit Live-KursGET /securities/:isin/timeseries– Kurshistorie- weitere:
/tick,/tradability,/buyable
Transaktionen und Tagesgeld
GET /transactions– paginiert, filterbar nach ISIN, Typ und StatusGET /savings,GET /savings/transactions
Streaming
GET /valuation/stream– SSE mit Live-Portfolio-BewertungGET /quotes/stream?isins=ISIN1,ISIN2– SSE mit Live-Kursen
Sonstiges
POST /proxy– roher GraphQL-DurchgriffGET /docs– Scalar-UI aus der OpenAPI-Spec
API-Änderungserkennung
Mit dem --monitor-Flag lässt sich Drift-Detection aktivieren. Das Tool vergleicht bei jeder Antwort die Struktur des Payloads gegen eine gespeicherte Baseline und schreibt Änderungen (neue oder fehlende Felder, Typwechsel) mit Zeitstempel in eine separate Datei. So fällt schnell auf, wenn Scalable Capital ihre interne API anpasst.
Sicherheit
Der Server bindet nur an localhost und ist damit nicht im Netzwerk erreichbar. Optional lässt sich ein Token-Header für alle Routen erzwingen. Die Session-Datei ist gitignored und wird mit restriktiven Dateirechten geschrieben.
Kein offizielles Projekt, keine Verbindung zu Scalable Capital. Nutzung auf eigene Verantwortung.
