API-Grundlagen

Aufbau der HTTP-API — Authentifizierung über Session-Cookie, stabiles Fehler-Format, Rate-Limits und die cross-origin nutzbaren Endpunkte.

Alle Endpunkte deiner Community liegen unter https://<deine-community>/api/… und antworten mit JSON.

Authentifizierung

Es gibt keine API-Schlüssel. Authentifiziert wird über ein HttpOnly-Session-Cookie, das beim Anmelden gesetzt wird:

  • Das Cookie ist HttpOnly, Secure und SameSite — JavaScript kommt nicht daran, und es reist nicht ungewollt zu fremden Seiten mit.
  • Requests aus dem Browser müssen es mitschicken (credentials: 'include' bei fetch, sofern nicht ohnehin same-origin).
  • Ein Server-zu-Server-Zugang für Drittsysteme existiert derzeit nicht.

Ohne gültige Sitzung antworten geschützte Routen mit 401, ohne ausreichende Rechte mit 403.

Fehler-Format

Fehler unterhalb von /api/ kommen in einem stabilen Umschlag zurück — gedacht dafür, dass du gegen feste Codes programmieren kannst statt gegen HTTP-Status zu raten:

{ "ok": false, "code": "VALIDATION_ERROR", "message": "targetId and targetType are required" }
CodeHTTPBedeutung
VALIDATION_ERROR400, 422Eingabe unvollständig oder ungültig
UNAUTHORIZED401Keine (gültige) Sitzung
FORBIDDEN403Angemeldet, aber nicht berechtigt
NOT_FOUND404Nicht vorhanden — oder für dich nicht sichtbar
CONFLICT409Zustand passt nicht (z. B. Adresse bereits belegt)
RATE_LIMITED429Zu viele Anfragen
INTERNAL_ERRORab 500Serverfehler

Ab 500 ist die message bewusst generisch: interne Details, Stacktraces und Datenbank-Meldungen verlassen den Server nicht.

404 steht auch dann, wenn etwas existiert, aber nicht zu deiner Community gehört. Das ist Absicht — die Antwort soll nicht verraten, dass es die Zeile anderswo gibt.

Rate-Limits

Gezählt wird pro IP in einem Fenster von einer Minute:

BereichGrenze pro Minute
Anmeldung, Code- und Passwort-Zurücksetzung5
Kommentare lesen (GET /api/comments, GET /api/comments/count)120
Schreiben (Kommentar, Beitrag, Vote, Meldung)60
Gast-Kommentare5

Ist die Grenze erreicht, kommt 429 mit code: "RATE_LIMITED". Bei Anmeldung und Code-Prüfung zählen nur fehlgeschlagene Versuche — ein erfolgreicher Login verbraucht das Budget nicht.

Cross-Origin

Nur ein Endpunkt ist bewusst von fremden Seiten aus abrufbar:

GET /api/comments/count?targetId=<id>&targetType=<typ>
→ { "count": 12 }

Er antwortet mit Access-Control-Allow-Origin: *, ist read-only, kommt ohne Cookies aus und enthält keine personenbezogenen Daten. Genau diesen Endpunkt nutzt embed.js für data-pukalani-count (siehe Embed-Widget).

Alle übrigen Endpunkte sind same-origin. Kommentare auf einer fremden Seite darstellen geht deshalb über das iframe-Widget, nicht über eigene fetch-Aufrufe.

Kommentare lesen (same-origin)

GET /api/comments?targetId=<id>&targetType=<typ>&sort=new&page=1
ParameterPflichtWerte
targetIdjaSchlüssel des Strangs
targetTypejaNamensraum, z. B. blog
sortneinnew (Default), top, trending, discussed
pageneinSeitenzahl ab 1

Paginiert wird über Top-Level-Stränge; jeder wird mit seinem kompletten Antwortbaum geliefert, damit keine Antwort ohne ihren Ausgangsbeitrag ankommt. Ausgeblendete Kommentare fehlen; vom Autor gelöschte bleiben als Platzhalter erhalten, damit der Strang lesbar bleibt.

Erreichbarkeit prüfen

GET /api/health
→ { "ok": true, "user": null, "build": "<commit>" }

Beantwortet auch HEAD — Uptime-Monitore und Load-Balancer prüfen oft so.

Echtzeit

Neue und geänderte Kommentare erreichen offene Browser über einen WebSocket, den die Oberfläche selbst aufbaut und authentifiziert. Eine öffentliche, dokumentierte Realtime-Schnittstelle für Fremdsysteme gibt es nicht — im eingebetteten Widget ist die Echtzeit-Aktualisierung aber ohne Zutun enthalten.