API

API-Schlüssel mit Geltungsbereichen, gebunden an Ihre Organisation. Bei jedem Build aus dem OpenAPI-Vertrag des Produkts neu erzeugt, damit diese Seite nicht vom Code abweichen kann.

API-Schlüssel sind da. Sie legen sie in der App unter Integrationen, API-Schlüssel an (nur Owner und Admin) und schicken sie als Bearer-Token:

Authorization: Bearer pst_...

Ein Schlüssel gehört zu genau einer Organisation. Er trägt Geltungsbereiche, nämlich monitors, incidents, status-pages und webhooks, jeweils als :read oder :write, dazu org:read; ein Schreibrecht schließt das Leserecht derselben Ressource ein. Sie können einen Schlüssel weiter verengen, auf ausgewählte Projekte oder auf einzelne Monitore. Widerruf und Ablauf greifen bei der nächsten Anfrage, nicht erst am Ende irgendeines Zwischenspeichers.

Schlüssel können keine Schlüssel verwalten. Die Verwaltungsendpunkte verlangen konstruktionsbedingt eine Browser-Sitzung. Ein abhandengekommener Schlüssel liest also, was seine Geltungsbereiche erlauben, und kann sich niemals selbst einen Nachfolger ausstellen.

Was heute einen Schlüssel annimmt

Die Schlüssel-Authentifizierung ist auf sieben lesenden Endpunkten aktiv:

Endpunktwas er liefert
Monitore eines Projektsdie Liste mit Zustand, Typ, Intervall, Regionen
ein einzelner Monitordie Detailansicht, wie das Cockpit sie zeigt
Checks eines Monitorsdie rohen Checkergebnisse dahinter
Zeitreihe eines MonitorsAntwortzeiten über einen Zeitraum
Incidents eines Monitorsdie Incidents an diesem Monitor
Incidents einer Organisationdie Liste
ein einzelner Incidentdie Detailansicht mit Zeitachse

Jeder andere Endpunkt unten verlangt weiterhin eine Sitzung, und Schreibrechte sind zwar wählbar, werden aber noch nirgends ausgewertet. Die kuratierte öffentliche Referenz in der Version 1.0.0-beta.1 folgt mit dem nächsten Release; bis dahin zeigt diese Seite den vollständigen Umfang, mit dem die Apps sprechen, damit Sie die Form dessen sehen, was kommt.

Funktionsbereiche, die nicht veröffentlicht sind, etwa mehrstufige Checks, bleiben ausgeschlossen, bis sie ausgeliefert werden.

Perstat API v0.1.0 · 168 dokumentierte Operationen · pro Build neu erzeugt

Auth and session

  • POST /auth/login
  • POST /auth/logout

    Beendet die aktuelle Sitzung serverseitig. Sitzungen sind einzeln und gesamthaft widerrufbar.

  • POST /auth/magic

    Magic-Link-Anmeldung: Der Endpunkt nimmt eine E-Mail-Adresse entgegen und verschickt einen einmaligen Anmeldelink. Antwortet bewusst neutral, unabhängig davon, ob die Adresse existiert.

  • POST /auth/magic/verify
  • POST /auth/register

    Onboarding: legt User + Organization + Owner-Membership an und loggt direkt ein (Bearer-Token). 201 bei Erfolg, 409 wenn E-Mail/Org-Slug schon existiert.

  • GET /me
  • GET /me/activity

    Aktivitätslog ÜBER ALLE Orgs des Users (Scope „Alle Organisationen").

  • GET /me/cockpit-bootstrap
  • GET /me/cockpit-stats
  • GET /me/devices

    Verbundene Push-Geräte des eingeloggten Users (ohne Roh-Token).

  • POST /me/devices

    Registriert ein Push-Device-Token für den angemeldeten User (Upsert). Grundlage für die spätere Push-Auslieferung bei Incidents.

  • DELETE /me/devices/{id}

    Entfernt ein verbundenes Gerät des Users.

  • GET /me/downtimes
  • GET /me/invitations
  • POST /me/invitations/{inv_id}/accept
  • POST /me/locale
  • GET /me/logins

    Letzte Anmeldungen (Sessions) des eingeloggten Users — neueste zuerst.

  • POST /me/logins/revoke-others

    Meldet alle anderen Sessions des Users ab („überall abmelden") — die aktuelle Session bleibt aktiv.

  • DELETE /me/logins/{id}

    Meldet eine bestimmte Session des Users ab (widerruft sie).

  • GET /me/notification-preferences
  • PUT /me/notification-preferences
  • GET /me/notifications

    Benachrichtigungen des eingeloggten Users (neueste zuerst, max. 30).

  • POST /me/notifications/read

    Markiert alle Benachrichtigungen des Users als gelesen.

  • GET /me/notifications/unread

    Anzahl ungelesener Benachrichtigungen (Glocken-Badge, billig pollbar).

  • GET /me/open-incidents

    Offene Incidents ÜBER ALLE Orgs des Users — für die globale Incident-Leiste (Scope „Alle Organisationen"). Älteste zuerst.

  • GET /me/org-summaries
  • GET /me/organizations
  • GET /me/phone
  • PUT /me/phone
  • POST /me/phone/verify

    Bestätigt die Nummer mit dem SMS-Code. `204` bei Erfolg, sonst `400` (kein Oracle: falsch/abgelaufen/zu viele Versuche → einheitlich 400).

  • POST /me/phone/verify/request

    Fordert einen 6-stelligen SMS-Code zur Verifizierung der EIGENEN Nummer an. Braucht eine gesetzte Nummer + konfiguriertes Twilio (`503` sonst). `429` bei aktivem Cooldown. Schon verifiziert → `200 {sent:false}`.

  • GET /me/raw-down-days
  • GET /me/region-capabilities

    Regionen-Katalog: IPv6-Fähigkeit (für die Regionen-Filterung im Monitor- Formular) plus Geo-Anreicherung aus der kanonischen Registry (ADR-0010) — Kontinent als Anzeige-Rollup und, wo betrieben, die PoP-Stadt/-Land für die nutzersichtbare Transparenz.

  • GET /me/region-summaries
  • GET /me/resolve-host

    Prüft, ob ein Host nach IPv4/IPv6 auflöst (bzw. eine IP-Literal ist). Das Formular nutzt das, um IPv6 nur anzubieten, wenn ein AAAA/IPv6 existiert. Reine DNS-Auflösung (keine Verbindung).

  • GET /me/timeline

    Konsolidierte Statuswechsel-Zeitleiste ÜBER ALLE Orgs des Users (Scope „Alle Organisationen").

  • GET /organizations/{org_id}/members
  • PATCH /organizations/{org_id}/members/{user_id}
  • DELETE /organizations/{org_id}/members/{user_id}

Organizations and members

  • POST /invitations/accept
  • POST /invitations/inspect

    Liest die Eckdaten einer offenen Einladung per Token — OHNE sie zu verbrauchen. Damit kann das Frontend vor der Annahme ein Bestätigungs-Modal (Org + Rolle) zeigen.

  • POST /organizations
  • PATCH /organizations/{org_id}
  • DELETE /organizations/{org_id}
  • GET /organizations/{org_id}/activity

    Aktivitätslog der Org: Konfig-Änderungen durch User/API (wer, wann, was).

  • POST /organizations/{org_id}/convert

    Konversion Trial→zahlend: setzt den lokalen Plan-Spiegel (Gating sofort) und synchronisiert best-effort mit dem ERP (Kunde + Firmendaten + Tarif). Nur Owner/BillingAdmin. Ohne ERP-Config bleibt die Konversion rein lokal (lazy ERP).

  • GET /organizations/{org_id}/downtimes
  • GET /organizations/{org_id}/entitlements
  • GET /organizations/{org_id}/invitations
  • POST /organizations/{org_id}/invitations
  • DELETE /organizations/{org_id}/invitations/{inv_id}
  • GET /organizations/{org_id}/project-summaries
  • GET /organizations/{org_id}/raw-down-days
  • GET /organizations/{org_id}/timeline

    Konsolidierte Statuswechsel-Zeitleiste der Org (was passierte wann).

Projects

  • GET /organizations/{org_id}/projects
  • POST /organizations/{org_id}/projects
  • POST /organizations/{org_id}/projects/reorder
  • PATCH /projects/{project_id}
  • DELETE /projects/{project_id}
  • GET /projects/{project_id}/activity

    Aktivitätslog EINES Projekts: Änderungen am Projekt, seinen Monitoren und Journeys.

  • GET /projects/{project_id}/downtimes
  • GET /projects/{project_id}/monitors
  • POST /projects/{project_id}/monitors
  • POST /projects/{project_id}/monitors/reorder
  • POST /projects/{project_id}/move

    Verschiebt ein Projekt in eine andere Organisation (mit Org-Cascade auf alle Dienste). Erfordert Manage-Rolle in Quell- UND Ziel-Org.

  • GET /projects/{project_id}/raw-down-days
  • GET /projects/{project_id}/timeline

    Statuswechsel-Zeitleiste EINES Projekts (gefiltert über die Monitore des Projekts).

Monitors and checks

  • PATCH /alert-profiles/{id}
  • DELETE /alert-profiles/{id}
  • GET /monitors/{monitor_id}
  • PATCH /monitors/{monitor_id}

    Aktualisiert einen Monitor (partiell). Auch fuer das Aktiv/Inaktiv-Schalten (`{ "enabled": false }`) genutzt — wie bei Journeys.

  • DELETE /monitors/{monitor_id}
  • GET /monitors/{monitor_id}/alarm-state
  • GET /monitors/{monitor_id}/checks
  • POST /monitors/{monitor_id}/clone
  • GET /monitors/{monitor_id}/incidents
  • POST /monitors/{monitor_id}/move

    Verschiebt einen Monitor in ein anderes Projekt (ggf. andere Org). Erfordert Manage-Rolle in Quell- UND Ziel-Org.

  • POST /monitors/{monitor_id}/run

    Fuehrt einen Monitor JETZT aus (interim In-API-Executor, vgl. run_journey).

  • GET /monitors/{monitor_id}/series
  • GET /organizations/{org_id}/alert-profiles
  • POST /organizations/{org_id}/alert-profiles
  • POST /organizations/{org_id}/monitors/{monitor_id}/discard-day

    Incident-losen roten Tag als Fehlalarm verwerfen: Tages-Exclusion-Fenster. Nur Owner/Admin, auditiert, per Restore umkehrbar.

Incidents and post-mortems

  • GET /organizations/{org_id}/incidents
  • POST /organizations/{org_id}/incidents
  • GET /organizations/{org_id}/incidents/feed

    Org-weite Incident-Liste für die Incidents-Seite: offene zuerst, dann die jüngsten gelösten (gedeckelt auf 200). Ergänzt `GET .../incidents` (nur offene, schlanke DTOs für Down-Markierungen), ersetzt es nicht.

  • GET /organizations/{org_id}/incidents/{incident_id}
  • POST /organizations/{org_id}/incidents/{incident_id}/ack
  • GET /organizations/{org_id}/incidents/{incident_id}/action-items
  • POST /organizations/{org_id}/incidents/{incident_id}/action-items
  • PUT /organizations/{org_id}/incidents/{incident_id}/action-items/{item_id}
  • DELETE /organizations/{org_id}/incidents/{incident_id}/action-items/{item_id}
  • POST /organizations/{org_id}/incidents/{incident_id}/assign
  • POST /organizations/{org_id}/incidents/{incident_id}/delete

    Incident-Meldung entfernen (Soft-Delete): verschwindet aus der öffentlichen Incident-Historie; Uptime/Balken bleiben unverändert. Nur Owner/Admin, nur RESOLVED, auditiert, per Restore umkehrbar.

  • POST /organizations/{org_id}/incidents/{incident_id}/discard-downtime

    Downtime als Fehlalarm verwerfen: das Fenster fällt aus Uptime %, Tages- balken und Badge heraus (statusseiten-wirksam); optional verschwindet auch die Incident-Meldung. Nur Owner/Admin, nur beendete Ausfälle, auditiert.

  • GET /organizations/{org_id}/incidents/{incident_id}/discard-preview

    Vorschau: wie ändert sich die Uptime (7/30/90 Tage), wenn dieses Fenster verworfen wird? Speist den Bestätigungs-Dialog VOR der Aktion.

  • GET /organizations/{org_id}/incidents/{incident_id}/events
  • POST /organizations/{org_id}/incidents/{incident_id}/note
  • GET /organizations/{org_id}/incidents/{incident_id}/on-call
  • POST /organizations/{org_id}/incidents/{incident_id}/on-call/ack
  • GET /organizations/{org_id}/incidents/{incident_id}/pages
  • POST /organizations/{org_id}/incidents/{incident_id}/pages
  • DELETE /organizations/{org_id}/incidents/{incident_id}/pages/{page_id}
  • GET /organizations/{org_id}/incidents/{incident_id}/postmortem
  • PUT /organizations/{org_id}/incidents/{incident_id}/postmortem
  • POST /organizations/{org_id}/incidents/{incident_id}/postmortem/publish
  • POST /organizations/{org_id}/incidents/{incident_id}/resolve
  • POST /organizations/{org_id}/incidents/{incident_id}/restore

    Gelöschte Incident-Meldung wiederherstellen.

  • POST /organizations/{org_id}/incidents/{incident_id}/restore-downtime

    Verworfene Downtime wiederherstellen — alle Aggregate heilen zurück.

  • POST /organizations/{org_id}/incidents/{incident_id}/severity
  • POST /organizations/{org_id}/incidents/{incident_id}/snooze

    Schlummert einen Incident für den AUFRUFER (nur ihn) für `SNOOZE_MINUTES` (15). Der Broadcast-/Owner-Push unterdrückt diese Person bis zum Ablauf; andere Mitarbeiter werden weiter normal alarmiert. KEIN Ack (übernimmt den Fall nicht).

  • POST /organizations/{org_id}/incidents/{incident_id}/summary

On-call and paging

  • GET /organizations/{org_id}/on-call/duty
  • GET /organizations/{org_id}/on-call/members
  • PUT /organizations/{org_id}/on-call/members
  • GET /organizations/{org_id}/on-call/settings
  • PUT /organizations/{org_id}/on-call/settings
  • GET /organizations/{org_id}/paging-usage

Status pages

  • GET /badge.svg

    ÖFFENTLICH: Badge unter der EIGENEN Custom-Domain — `https://<domain>/badge.svg`. Der Edge reicht den `Host`-Header an die API durch; wir lösen die Domain via [`StatusPageRepository::find_public_by_domain`] auf die Seite auf. So kann der Badge-Embed dieselbe (kurze) Domain wie der Link nutzen, statt der API-URL. (Auf der Wildcard-Subdomain existiert keine Domain-Row → 404; dort nutzt das Frontend weiter die `/public/status-pages/{slug}/badge.svg`-URL.)

  • GET /organizations/{org_id}/status-pages
  • POST /organizations/{org_id}/status-pages
  • GET /organizations/{org_id}/status-pages/archived
  • GET /public/status-pages/resolve

    Public: löst eine Custom-Domain (Host-Header oder `?host=`) auf den Slug der zugehörigen, publizierten Status-Seite auf. Kein Auth.

  • GET /public/status-pages/{slug}

    ÖFFENTLICH (kein Auth). Liefert eine publizierte Status-Seite anhand ihres Slugs: Komponenten = die handverlesenen Monitore (NUR über den Page-Join, nie eine Monitor-ID vom Aufrufer) mit aktuellem Status + Uptime%. Keine internen/Tenant-IDs in der Antwort.

  • GET /public/status-pages/{slug}/badge.svg

    ÖFFENTLICH: einbettbares SVG-Status/Uptime-Badge einer Status-Seite. `?metric=uptime` zeigt die aggregierte Uptime% statt des Gesamtstatus.

  • GET /public/status-pages/{slug}/feed.rss

    ÖFFENTLICH: RSS-2.0-Feed der Incidents + geplanten Wartungen einer Status-Seite. Reuse der bereits öffentlichen Daten hinter demselben Sichtbarkeits-Gate.

  • POST /public/status-pages/{slug}/login

    ÖFFENTLICH (rate-limited): Login eines Viewers einer privaten Status-Seite. Erfolg → langlebiges Viewer-Token. Bei jedem Fehlschlag einheitlich `401` (keine Unterscheidung „User unbekannt" vs. „Passwort falsch" → kein Enum-Oracle).

  • GET /public/status-pages/{slug}/logo

    ÖFFENTLICH: Logo einer publizierten Status-Seite (per Slug).

  • GET /public/status-pages/{slug}/logo/dark

    ÖFFENTLICH: Dark-Mode-Logo einer publizierten Status-Seite (per Slug).

  • POST /public/status-pages/{slug}/subscribe

    ÖFFENTLICH (rate-limited): Abo-Anfrage für Statusseiten-Updates (Double-Opt-in). Antwortet immer `202` (außer ungültige Adresse → `400` / unbekannte Seite → `404`) — verrät nie, ob die Adresse neu oder schon bestätigt ist. Eine Bestätigungsmail geht NUR bei neuem oder noch unbestätigtem Abo raus.

  • POST /public/status-pages/{slug}/unlock

    ÖFFENTLICH (rate-limited): EIN geteiltes Kennwort schaltet die ganze Seite frei. Erfolg → langlebiges Shared-Token im HttpOnly-Cookie `sp_unlock_<slug>` (kein Token im Body — Cookie-only, damit kein geteilter Link den Zugang leckt). Bei jedem Fehlschlag einheitlich `401` (kein Oracle); Seite ohne Shared-Modus → `404`.

  • GET /status-pages/{id}
  • PATCH /status-pages/{id}
  • DELETE /status-pages/{id}
  • GET /status-pages/{id}/domains
  • POST /status-pages/{id}/domains
  • POST /status-pages/{id}/domains/reorder

    Reihenfolge der Custom-Domains setzen (Drag&Drop). Die ERSTE Domain ist der Default-Host, der überall verlinkt wird (Badge + obere URL der Editor-Kachel).

  • DELETE /status-pages/{id}/domains/{domain_id}
  • POST /status-pages/{id}/domains/{domain_id}/verify

    Synchroner Verify-Klick: DNS prüfen (CNAME); bei Erfolg verifizieren + (falls Edge konfiguriert) als VHost pushen. Liefert den aktuellen Stand.

  • DELETE /status-pages/{id}/logo
  • DELETE /status-pages/{id}/logo/dark
  • POST /status-pages/{id}/monitors
  • PUT /status-pages/{id}/shared-password

    Operator: geteiltes Kennwort setzen/rotieren. Das Setzen ist der EINZIGE Pfad, der `shared_password_hash` befüllt (nie die Settings-PUT). Rotation invalidiert alle bestehenden Shared-Cookies (delete_shared_sessions). Min. 12 Zeichen.

  • DELETE /status-pages/{id}/shared-password

    Operator: geteiltes Kennwort entfernen (Modus aus, Hash leeren, Sessions weg).

  • GET /status-pages/{id}/subscribers

    Operator: bestätigte Abonnenten einer Status-Seite auflisten. Nur Operator (`can_manage_projects`) — die E-Mails sind PII. BEWUSST nicht cap-gegated, damit eine herabgestufte Org ihren Bestand noch einsehen/aufräumen kann.

  • DELETE /status-pages/{id}/subscribers/{subscriber_id}

    Operator: einen Abonnenten entfernen (per interner id, gescopt auf die Seite).

  • POST /status-pages/{id}/unarchive
  • GET /status-pages/{id}/versions
  • POST /status-pages/{id}/versions
  • POST /status-pages/{id}/versions/{version_id}/restore
  • GET /status-pages/{id}/viewers

    Operator: Viewer einer (privaten) Status-Seite auflisten.

  • POST /status-pages/{id}/viewers

    Operator: Viewer anlegen. Passwort wird generiert + EINMALIG zurückgegeben.

  • DELETE /status-pages/{id}/viewers/{viewer_id}

    Operator: Viewer entfernen (seine Sessions kaskadieren mit).

Maintenance and curation

  • POST /organizations/{org_id}/exclusions/{exclusion_id}/restore

    Manuelles Tages-Fenster zurücknehmen — der Tag zählt wieder wie gemessen.

  • GET /organizations/{org_id}/maintenance-windows
  • POST /organizations/{org_id}/maintenance-windows
  • PATCH /organizations/{org_id}/maintenance-windows/{id}
  • DELETE /organizations/{org_id}/maintenance-windows/{id}
  • POST /organizations/{org_id}/maintenance-windows/{id}/cancel

Host agents

  • POST /organizations/{org_id}/agent-enroll-tokens

    `POST /organizations/{org_id}/agent-enroll-tokens`: erzeugt ein Enrollment- Token (UI). Erfordert Projektverwaltungs-Rechte.

  • GET /organizations/{org_id}/agents

    `GET /organizations/{org_id}/agents`: aktive Agents der Org (Listenanzeige).

  • PATCH /organizations/{org_id}/agents/{agent_id}

    `PATCH /organizations/{org_id}/agents/{agent_id}`: erweiterte Konfiguration eines Agents (v1: nur das Inventar-Opt-in). Erfordert Projektverwaltungs- Rechte. Der Agent übernimmt das Flag beim nächsten Config-Poll (~5 min).

  • DELETE /organizations/{org_id}/agents/{agent_id}

    `DELETE /organizations/{org_id}/agents/{agent_id}`: entfernt einen Agent (soft-delete) — das Per-Agent-Token wird sofort ungültig und der Agent verschwindet aus der Liste. Erfordert Projektverwaltungs-Rechte. Die rückstandslose Entfernung VOM HOST erfolgt separat (uninstall.sh).

Webhooks

  • GET /organizations/{org_id}/webhooks
  • POST /organizations/{org_id}/webhooks
  • PATCH /organizations/{org_id}/webhooks/{target_id}
  • DELETE /organizations/{org_id}/webhooks/{target_id}
  • POST /organizations/{org_id}/webhooks/{target_id}/rotate-secret

    Neues Signatur-Secret setzen (nur kind=webhook). Antwort trägt das volle Secret genau EINMAL; alte Signaturen sind ab sofort ungültig.

  • POST /organizations/{org_id}/webhooks/{target_id}/test

    Test-Zustellung (synchron, Timeout 10s): sendet ein `incident.test`-Ereignis an GENAU dieses Ziel und hält das Ergebnis als letzten Versuch fest.