Skip to content

API-Referenz ​

Maßgebliche, stets aktuelle Referenz

Die interaktive Reseller-API-Referenz wird direkt aus der laufenden API generiert und ist immer mit der Produktion synchron. Melde dich als Reseller an und öffne:

app.hoppla.dev/api/v1/reseller/docs (Reseller-Login erforderlich)

Sie dokumentiert jeden Endpunkt mit Request-/Response-Schemas und dem genauen Token-Scope, den er benötigt. Die folgende Anleitung ist eine konzeptionelle Übersicht.

Vollständige Referenz der Hoppla Reseller API.

Base URL ​

https://app.hoppla.dev/api/v1

Authentifizierung ​

Alle Endpoints brauchen ein Bearer Token, das du über POST /auth/token bekommst.

Authorization: Bearer {token}

Rate-Limiting ​

Reseller-Endpoints sind auf 120 Anfragen pro Minute begrenzt. Bei Überschreitung liefert die API 429 Too Many Requests mit einem Retry-After Header.

Fehlerformat ​

Alle Fehlerantworten folgen dieser Struktur:

json
{
  "message": "Human-readable error description",
  "errors": {
    "field_name": ["Validation error message"]
  }
}
StatusBedeutung
401Fehlender oder ungültiger Authentifizierungs-Token
403Unzureichende Berechtigungen (kein Reseller, oder das Team gehört nicht zu dir)
404Ressource nicht gefunden
422Validierung fehlgeschlagen
429Rate-Limit überschritten

Authentifizierungs-Endpoints ​

Token erstellen ​

API-Token durch Eintausch deiner Zugangsdaten erhalten.

POST /auth/token

Rate-Limit: throttle:auth (strenger als das Standard-API-Limit)

Request Body:

FeldTypPflichtBeschreibung
emailstringjaE-Mail-Adresse deines Kontos
passwordstringjaPasswort deines Kontos
device_namestringjaBezeichner für den Token (z. B. "CI Server")

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "secret",
    "device_name": "Integration"
  }'

Antwort (201):

json
{
  "token": "ss-aB3dLookup9xKsecretValue1234...",
  "user": {
    "id": "9a1b2c3d-e5f6-...",
    "name": "Reseller Account",
    "email": "[email protected]",
    "tenant_id": "tenant-uuid-...",
    "role": "admin",
    "language": "en",
    "managed_teams": [
      {
        "id": "mt-uuid-...",
        "tenant_id": "managed-tenant-uuid-...",
        "name": "Acme Corp",
        "slug": "acme-corp",
        "label": "Enterprise Client"
      }
    ]
  }
}

Bei Reseller-Konten enthält die Antwort ein managed_teams-Array mit allen Teams, die du verwaltest.

Token-Format: Alle Hoppla-Tokens sind undurchsichtige, mit einem Präfix versehene Zeichenketten, die bei der Erstellung nur einmal angezeigt werden: Session-Tokens beginnen mit ss-, Reseller-Verwaltungstokens mit rk-, Impersonation-Tokens mit ik- und Service-API-Keys verwalteter Teams mit svc-. Bewahr sie sicher auf -- sie können nicht erneut abgerufen werden. Für Server-zu-Server-Automatisierung empfehlen wir statt eines Session-Tokens ein eigenes Reseller-Verwaltungstoken (rk-…); siehe Reseller API Tokens.

Aktuellen Benutzer abrufen ​

GET /user

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/user \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "id": "9a1b2c3d-e5f6-...",
  "name": "Reseller Account",
  "email": "[email protected]",
  "tenant_id": "tenant-uuid-...",
  "role": "admin",
  "language": "en"
}

Token widerrufen ​

DELETE /auth/token

Beispiel:

bash
curl -X DELETE https://app.hoppla.dev/api/v1/auth/token \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "message": "Token revoked"
}

Verwaltete Teams ​

Alle Endpoints unter /reseller/managed-teams brauchen die Rolle Reseller. Du kannst nur auf Teams zugreifen, die deinem Mandanten zugeordnet sind.

Verwaltete Teams auflisten ​

GET /reseller/managed-teams

Query-Parameter:

ParameterTypStandardBeschreibung
pageinteger1Seitennummer
per_pageinteger15Einträge pro Seite

Beispiel:

bash
curl "https://app.hoppla.dev/api/v1/reseller/managed-teams?page=1" \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": [
    {
      "id": "mt-uuid-...",
      "tenant_id": "tenant-uuid-...",
      "name": "Acme Corp",
      "slug": "acme-corp",
      "plan": "starter",
      "label": "Enterprise Client #42",
      "monitors_count": 12,
      "monitors_down_count": 1,
      "monitors_up_count": 10,
      "is_paused": false,
      "paused_at": null,
      "paused_reason": null,
      "on_trial": false,
      "trial_ends_at": null,
      "deleted_at": null,
      "days_until_purge": null,
      "created_at": "2026-01-15T10:30:00.000000Z",
      "updated_at": "2026-01-15T10:30:00.000000Z"
    }
  ],
  "links": { "first": "...", "last": "...", "prev": null, "next": null },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1 }
}

Verwaltetes Team anlegen ​

Neuen Mandanten mit optionalem Admin-Benutzer provisionieren.

POST /reseller/managed-teams

Request Body:

FeldTypPflichtBeschreibung
namestringjaAnzeigename des Teams (max. 255 Zeichen)
slugstringjaURL-sicherer Bezeichner (Kleinbuchstaben, nur Bindestriche, max. 100 Zeichen, eindeutig)
planstringneinTarifmodell: free, hobby, starter oder pro (Standard: free)
labelstringneinInternes Label für deine Referenz (max. 255 Zeichen)
admin_emailstringneinE-Mail-Adresse für den Admin-Benutzer des Teams
admin_namestringneinName des Admin-Benutzers des Teams
admin_passwordstringbedingtPflicht, wenn admin_email angegeben wird (min. 12 Zeichen, wird gegen Datenleck-Datenbanken geprüft)
trial_daysintegerneinDas Team mit einer Testphase starten (1–365 Tage). Der Tarif des Teams gilt während der Testphase und fällt nach Ablauf auf free zurück.

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "slug": "acme-corp",
    "plan": "starter",
    "trial_days": 14,
    "label": "Enterprise Client #42",
    "admin_email": "[email protected]",
    "admin_name": "Jane Doe",
    "admin_password": "securepass12345"
  }'

Antwort (201):

json
{
  "data": {
    "id": "mt-uuid-...",
    "tenant_id": "new-tenant-uuid-...",
    "name": "Acme Corp",
    "slug": "acme-corp",
    "plan": "starter",
    "label": "Enterprise Client #42",
    "monitors_count": 0,
    "monitors_down_count": 0,
    "monitors_up_count": 0,
    "is_paused": false,
    "paused_at": null,
    "paused_reason": null,
    "on_trial": false,
    "trial_ends_at": null,
    "deleted_at": null,
    "days_until_purge": null,
    "created_at": "2026-01-15T10:30:00.000000Z",
    "updated_at": "2026-01-15T10:30:00.000000Z"
  }
}

Dabei wird auch ein team.provisioned Webhook-Event ausgelöst.

Verwaltetes Team abrufen ​

GET /reseller/managed-teams/{id}

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-... \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "id": "mt-uuid-...",
    "tenant_id": "tenant-uuid-...",
    "name": "Acme Corp",
    "slug": "acme-corp",
    "plan": "starter",
    "label": "Enterprise Client #42",
    "monitors_count": 12,
    "monitors_down_count": 1,
    "monitors_up_count": 10,
    "is_paused": false,
    "paused_at": null,
    "paused_reason": null,
    "on_trial": false,
    "trial_ends_at": null,
    "deleted_at": null,
    "days_until_purge": null,
    "created_at": "2026-01-15T10:30:00.000000Z",
    "updated_at": "2026-01-15T10:30:00.000000Z"
  }
}

Verwaltetes Team aktualisieren ​

PATCH /reseller/managed-teams/{id}

Request Body:

FeldTypPflichtBeschreibung
namestringneinAnzeigename des Teams
labelstringneinInternes Label
planstringneinTarifmodell: free, hobby, starter oder pro
trial_daysintegerneinEine Testphase setzen (1–365 Tage ab jetzt). Nutze 0, um eine aktive Testphase zu beenden.

Beispiel:

bash
curl -X PATCH https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"label": "Updated Label", "plan": "pro", "trial_days": 30}'

Antwort (200):

json
{
  "data": {
    "id": "mt-uuid-...",
    "tenant_id": "tenant-uuid-...",
    "name": "Acme Corp",
    "slug": "acme-corp",
    "plan": "pro",
    "label": "Updated Label",
    "monitors_count": 12,
    "monitors_down_count": 1,
    "monitors_up_count": 10,
    "is_paused": false,
    "paused_at": null,
    "paused_reason": null,
    "on_trial": false,
    "trial_ends_at": null,
    "deleted_at": null,
    "days_until_purge": null,
    "created_at": "2026-01-15T10:30:00.000000Z",
    "updated_at": "2026-01-15T10:30:00.000000Z"
  }
}

Verwaltetes Team löschen ​

Setzt das verwaltete Team und den zugehörigen Mandanten auf gelöscht (Soft Delete). Das Team durchläuft eine 30-tägige Schonfrist, in der es wiederhergestellt werden kann. Nach Ablauf der Schonfrist werden das Team und alle seine Daten unwiderruflich entfernt.

DELETE /reseller/managed-teams/{id}

Request Body:

FeldTypPflichtBeschreibung
confirm_namestringjaMuss exakt dem Team-Namen entsprechen, um die Löschung zu bestätigen

Beispiel:

bash
curl -X DELETE https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"confirm_name": "Acme Corp"}'

Antwort (204): Kein Inhalt.

Dabei wird ein team.deleted Webhook-Event ausgelöst. Das Team kann innerhalb von 30 Tagen über den Wiederherstellungs-Endpoint wiederhergestellt werden. Nach Ablauf der Schonfrist werden alle Daten (Monitore, Vorfälle usw.) unwiderruflich entfernt.

Verwaltetes Team pausieren ​

Pausiert vorübergehend das gesamte Monitoring eines verwalteten Teams. Erfordert den Scope teams:write.

POST /reseller/managed-teams/{id}/pause

Request Body:

FeldTypPflichtBeschreibung
reasonstringneinGrund für das Pausieren (max. 50 Zeichen)

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../pause \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"reason": "maintenance"}'

Antwort (200):

json
{
  "data": {
    "message": "Team has been paused.",
    "is_paused": true,
    "paused_reason": "maintenance"
  }
}

Verwaltetes Team fortsetzen ​

Setzt das Monitoring eines pausierten verwalteten Teams fort. Erfordert den Scope teams:write.

POST /reseller/managed-teams/{id}/unpause

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../unpause \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "message": "Team has been unpaused.",
    "is_paused": false
  }
}

Gelöschte Teams auflisten ​

Listet auf gelöscht gesetzte (Soft Delete) verwaltete Teams auf, die sich noch innerhalb ihrer 30-tägigen Schonfrist befinden. Erfordert den Scope teams:read.

GET /reseller/managed-teams/trashed

Query-Parameter:

ParameterTypStandardBeschreibung
pageinteger1Seitennummer
per_pageinteger15Einträge pro Seite

Beispiel:

bash
curl "https://app.hoppla.dev/api/v1/reseller/managed-teams/trashed" \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

Paginierte Liste der auf gelöscht gesetzten Teams. Jedes Team enthält die Felder deleted_at und days_until_purge, die angeben, wann das Team gelöscht wurde und wie viele Tage bis zur endgültigen Entfernung verbleiben.

json
{
  "data": [
    {
      "id": "mt-uuid-...",
      "tenant_id": "tenant-uuid-...",
      "name": "Old Corp",
      "slug": "old-corp",
      "plan": "starter",
      "label": "Decommissioned",
      "monitors_count": 5,
      "monitors_down_count": 0,
      "monitors_up_count": 0,
      "is_paused": false,
      "paused_at": null,
      "paused_reason": null,
      "on_trial": false,
      "trial_ends_at": null,
      "deleted_at": "2026-03-10T12:00:00.000000Z",
      "days_until_purge": 25,
      "created_at": "2026-01-01T10:00:00.000000Z",
      "updated_at": "2026-03-10T12:00:00.000000Z"
    }
  ],
  "links": { "first": "...", "last": "...", "prev": null, "next": null },
  "meta": { "current_page": 1, "last_page": 1, "per_page": 15, "total": 1 }
}

Verwaltetes Team wiederherstellen ​

Stellt ein auf gelöscht gesetztes verwaltetes Team wieder her. Muss innerhalb der 30-tägigen Schonfrist erfolgen. Erfordert den Scope teams:write.

POST /reseller/managed-teams/{id}/restore

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../restore \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

Liefert das wiederhergestellte Team als Standard-ManagedTeamResource mit deleted_at auf null.

json
{
  "data": {
    "id": "mt-uuid-...",
    "tenant_id": "tenant-uuid-...",
    "name": "Old Corp",
    "slug": "old-corp",
    "plan": "starter",
    "label": "Decommissioned",
    "monitors_count": 5,
    "monitors_down_count": 0,
    "monitors_up_count": 0,
    "is_paused": false,
    "paused_at": null,
    "paused_reason": null,
    "on_trial": false,
    "trial_ends_at": null,
    "deleted_at": null,
    "days_until_purge": null,
    "created_at": "2026-01-01T10:00:00.000000Z",
    "updated_at": "2026-03-15T08:00:00.000000Z"
  }
}

Team-Zusammenfassung abrufen ​

Liefert einen Überblick über den Monitoring-Zustand des verwalteten Teams.

GET /reseller/managed-teams/{id}/summary

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../summary \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "monitors_count": 12,
    "monitors_up": 10,
    "monitors_down": 1,
    "active_incidents": 1,
    "notification_channels_count": 3,
    "status_pages_count": 2,
    "members_count": 5
  }
}

Team-Nutzung abrufen ​

Liefert Nutzungsmetriken für die Abrechnung. Akzeptiert einen optionalen period-Query-Parameter, um die Nutzung für einen bestimmten Monat abzurufen.

GET /reseller/managed-teams/{id}/usage

Query-Parameter:

ParameterTypStandardBeschreibung
periodstringaktueller MonatMonat im Format YYYY-MM (z. B. 2026-03)

Beispiel:

bash
curl "https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../usage?period=2026-03" \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "tenant_id": "tenant-uuid-...",
    "period": "2026-03",
    "monitors_count": 12,
    "checks_count": 43200,
    "api_requests_count": 1500,
    "notifications_sent_count": 42,
    "webhook_deliveries_count": 30
  }
}

Reseller-API-Tokens ​

Erstelle Scoped Tokens speziell für Reseller-Operationen. Diese Tokens haben granulare Berechtigungen und können ausschließlich auf Reseller-Verwaltungs-Endpoints zugreifen.

Verfügbare Scopes ​

Die meisten Domänen bieten eine Read/Write-Aufteilung plus eine :manage-Variante, die sowohl :read als auch :write für diese Domäne gewährt.

ScopeBeschreibung
teams:readVerwaltete Teams, Zusammenfassungen, Nutzung, Feature-Overrides, Templates, Provisionierungsprofile sowie mandantenübergreifende Übersicht/Berichte auflisten und anzeigen
teams:writeVerwaltete Teams erstellen, aktualisieren, löschen, pausieren, fortsetzen, wiederherstellen; Templates, Provisionierungsprofile, Batch-Operationen und Impersonation-Tokens verwalten
members:readMitglieder und Einladungen verwalteter Teams auflisten
members:writeTeam-Mitglieder erstellen, aktualisieren, löschen; Einladungen verwalten; MFA zurücksetzen
members:manageVollständige Mitgliederverwaltung (gewährt sowohl members:read als auch members:write)
branding:readBranding-Konfiguration verwalteter Teams anzeigen
branding:writeBranding-Konfiguration verwalteter Teams aktualisieren
branding:manageVollständige Branding-Verwaltung (gewährt sowohl branding:read als auch branding:write)
sso:readPartner-SSO-Konfiguration anzeigen
sso:writePartner-SSO-Konfiguration aktualisieren, Secrets rotieren, SSO-Links erzeugen
sso:manageVollständige SSO-Verwaltung (gewährt sowohl sso:read als auch sso:write)
portal:readPortal-Einstellungen, Custom Domains und E-Mail-Unterdrückung anzeigen
portal:writePortal-Einstellungen aktualisieren, Custom Domains verwalten, E-Mail-Unterdrückung aktualisieren
portal:manageVollständige Portal-Verwaltung (gewährt sowohl portal:read als auch portal:write)
api-keys:readAPI-Keys verwalteter Teams auflisten
api-keys:writeAPI-Keys verwalteter Teams erstellen und widerrufen
api-keys:manageVollständige API-Key-Verwaltung (gewährt sowohl api-keys:read als auch api-keys:write)
webhooks:readReseller-Webhooks auflisten und Zustellungsprotokolle anzeigen
webhooks:writeReseller-Webhooks erstellen, aktualisieren und löschen
webhooks:manageVollständige Webhook-Verwaltung (gewährt sowohl webhooks:read als auch webhooks:write)
notifications:readBenachrichtigungskanäle und -regeln eines verwalteten Teams anzeigen
notifications:writeBenachrichtigungskanäle und -regeln eines verwalteten Teams erstellen, aktualisieren und löschen
notifications:manageVollständige Benachrichtigungs-Verwaltung (gewährt sowohl notifications:read als auch notifications:write)
maintenance:readWartungsfenster eines verwalteten Teams anzeigen
maintenance:writeWartungsfenster eines verwalteten Teams erstellen, aktualisieren und löschen
maintenance:manageVollständige Wartungs-Verwaltung (gewährt sowohl maintenance:read als auch maintenance:write)
status-pages:readStatusseiten eines verwalteten Teams anzeigen
status-pages:writeStatusseiten eines verwalteten Teams erstellen, aktualisieren und löschen
status-pages:manageVollständige Statusseiten-Verwaltung (gewährt sowohl status-pages:read als auch status-pages:write)
monitors:readMonitore, Checks und Zeitreihen-Daten eines verwalteten Teams anzeigen
monitors:writeMonitore und Checks eines verwalteten Teams erstellen, aktualisieren, löschen, aktivieren/deaktivieren, Läufe anfordern und stummschalten
monitors:manageVollständige Monitor-Verwaltung (gewährt sowohl monitors:read als auch monitors:write)
incidents:readVorfälle eines verwalteten Teams anzeigen
incidents:writeVorfälle eines verwalteten Teams aktualisieren und schließen
incidents:manageVollständige Vorfall-Verwaltung (gewährt sowohl incidents:read als auch incidents:write)

Insgesamt gibt es 12 Scope-Domänen: teams, members, branding, sso, portal, api-keys, webhooks, notifications, maintenance, status-pages, monitors und incidents. Jede Domäne bietet :read, :write und eine :manage-Variante (die beides gewährt).

Verfügbare Scopes auflisten ​

GET /reseller/tokens/scopes

Antwort (200):

json
{
  "data": [
    { "value": "teams:read", "description": "List and view managed teams, summaries, usage, and feature overrides" },
    { "value": "teams:write", "description": "Create, update, delete, pause, unpause, and restore managed teams" }
  ]
}

Reseller-Tokens auflisten ​

GET /reseller/tokens

Antwort (200):

json
{
  "data": [
    {
      "id": "token-uuid-...",
      "name": "CI/CD Pipeline",
      "scopes": ["teams:read", "teams:write"],
      "purpose": "reseller",
      "is_active": true,
      "last_used_at": "2026-03-10T14:00:00.000000Z",
      "expires_at": null,
      "created_at": "2026-03-01T10:00:00.000000Z"
    }
  ]
}

Reseller-Token anzeigen ​

Ruft einen einzelnen Reseller-Token anhand seiner ID ab. Erfordert den Scope teams:read.

GET /reseller/tokens/{id}

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/reseller/tokens/token-uuid-... \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "id": "token-uuid-...",
    "name": "CI/CD Pipeline",
    "scopes": ["teams:read", "teams:write"],
    "purpose": "reseller",
    "is_active": true,
    "last_used_at": "2026-03-10T14:00:00.000000Z",
    "expires_at": null,
    "created_at": "2026-03-01T10:00:00.000000Z"
  }
}

Reseller-Token erstellen ​

POST /reseller/tokens

Request Body:

FeldTypPflichtBeschreibung
namestringjaToken-Name (max. 255 Zeichen)
scopesstring[]jaArray von Scope-Werten (min. 1)
expires_atdatetimeneinAblaufdatum (ISO 8601). Weglassen für keinen Ablauf

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/tokens \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Provisioning Script",
    "scopes": ["teams:read", "teams:write", "members:manage"],
    "expires_at": "2026-12-31T23:59:59Z"
  }'

Antwort (201):

json
{
  "data": {
    "id": "token-uuid-...",
    "name": "Provisioning Script",
    "scopes": ["teams:read", "teams:write", "members:manage"],
    "purpose": "reseller",
    "is_active": true,
    "last_used_at": null,
    "expires_at": "2026-12-31T23:59:59.000000Z",
    "created_at": "2026-03-10T10:00:00.000000Z"
  },
  "plain_text_token": "rk-secretResellerTokenValue123..."
}

Wichtig: Das plain_text_token wird nur einmal zurückgegeben. Bewahre es sicher auf. Reseller-Verwaltungstokens beginnen mit rk-; danach zeigt die Liste nur noch einen maskierten Stub (z. B. rk-...aB3d).

Reseller-Token rotieren ​

Erstellt einen Ersatz-Token mit demselben Namen und denselben Scopes. Der alte Token erhält eine Schonfrist (Standard: 24 Stunden), in der beide Tokens funktionieren, was Deployments ohne Ausfallzeit ermöglicht.

POST /reseller/tokens/{id}/rotate

Request Body:

FeldTypPflichtBeschreibung
grace_period_hoursintegerneinWie lange der alte Token gültig bleibt (1–168 h, Standard: 24)

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/tokens/token-uuid-.../rotate \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"grace_period_hours": 4}'

Antwort (201):

json
{
  "data": {
    "id": "new-token-uuid-...",
    "name": "CI Pipeline",
    "scopes": ["teams:read", "teams:write"],
    "purpose": "reseller",
    "is_active": true,
    "last_used_at": null,
    "expires_at": null,
    "created_at": "2026-03-10T14:00:00.000000Z"
  },
  "plain_text_token": "rk-newSecretResellerTokenValue...",
  "rotated_from": {
    "id": "old-token-uuid-...",
    "expires_at": "2026-03-11T14:00:00.000000Z",
    "grace_period_hours": 24
  }
}

Rotations-Workflow: (1) Rotate aufrufen, (2) das neue plain_text_token in deine Services ausrollen, (3) sobald die Funktion bestätigt ist, den alten Token widerrufen. Während der Schonfrist funktionieren beide Tokens.

Reseller-Token aktivieren/deaktivieren ​

Schaltet den Aktiv-Status eines Tokens um, ohne ihn zu löschen. Deaktivierte Tokens werden bei der Authentifizierung sofort abgelehnt, können aber jederzeit wieder aktiviert werden.

POST /reseller/tokens/{id}/toggle

Antwort (200):

json
{
  "data": {
    "id": "token-uuid-...",
    "name": "CI Pipeline",
    "scopes": ["teams:read", "teams:write"],
    "purpose": "reseller",
    "is_active": false,
    "last_used_at": "2026-03-10T12:00:00.000000Z",
    "expires_at": null,
    "created_at": "2026-03-01T10:00:00.000000Z"
  }
}

Anwendungsfall: Einen Token während Wartungsarbeiten oder bei der Incident-Bearbeitung vorübergehend deaktivieren, ohne die Token-Konfiguration zu verlieren. Erneut umschalten, um ihn wieder zu aktivieren.

Reseller-Token löschen ​

Entfernt den Token unwiderruflich. Nutze stattdessen Toggle (siehe oben), wenn du ihn nur vorübergehend deaktivieren möchtest.

DELETE /reseller/tokens/{id}

Antwort (204): Kein Inhalt.

Token-Voraussetzungen für Reseller-Endpoints ​

Reseller-Verwaltungs-Endpoints stellen zwei Zugriffsvoraussetzungen, die beide erfüllt sein müssen:

  1. Dein Mandant muss ein Reseller-Konto sein.
  2. Du musst dich mit einem Reseller-Token (rk-…) authentifizieren, das den passenden Scope für den Endpoint trägt.

Ein allgemeines read- (oder write-)Token gewährt keinen Zugriff auf Reseller-Verwaltungs-Endpoints -- auch nicht auf reine Lese-Endpoints. Erstell ein Reseller-Token mit den benötigten Scopes (siehe Reseller-Token erstellen).

Token-TypZugriff auf Reseller-Verwaltungs-Endpoints
Allgemeiner Token (beliebiger Scope)Kein Zugriff auf Reseller-Verwaltungs-Endpoints
Reseller-Token mit teams:readVerwaltete Teams auflisten/anzeigen
Reseller-Token mit teams:writeVerwaltete Teams erstellen/aktualisieren/löschen
Reseller-Token mit monitors:readMonitore und Checks eines verwalteten Teams anzeigen
Reseller-Token mit monitors:writeMonitore und Checks eines verwalteten Teams verwalten

Impersonation-Tokens ​

Erstelle kurzlebige Tokens, um im Mandanten-Kontext eines verwalteten Teams zu agieren. Diese Tokens sind für automatisierte mandantenübergreifende Operationen gedacht und werden im Audit-Trail protokolliert.

Aktive Impersonation-Tokens auflisten ​

GET /reseller/managed-teams/{id}/impersonation-tokens

Liefert nur nicht abgelaufene Tokens.

Antwort (200):

json
{
  "data": [
    {
      "id": "token-uuid-...",
      "name": "Impersonation: Acme Corp",
      "scopes": ["read", "write"],
      "expires_at": "2026-03-10T14:15:00.000000Z",
      "impersonated_by_user_id": "reseller-user-uuid-...",
      "created_at": "2026-03-10T14:00:00.000000Z"
    }
  ]
}

Impersonation-Token erstellen ​

POST /reseller/managed-teams/{id}/impersonation-tokens

Request Body:

FeldTypPflichtBeschreibung
ttl_minutesintegerneinLebensdauer des Tokens in Minuten (1–15, Standard: 15)
scopesstring[]neinArray aus "read" und/oder "write" (Standard: beide)
labelstringneinBeschreibendes Label für Audit-Zwecke (max. 255 Zeichen)

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../impersonation-tokens \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ttl_minutes": 10, "scopes": ["read"], "label": "Sync monitors"}'

Antwort (201):

json
{
  "data": {
    "id": "token-uuid-...",
    "managed_team_id": "mt-uuid-...",
    "managed_tenant_id": "tenant-uuid-...",
    "scopes": ["read"],
    "expires_at": "2026-03-10T14:10:00.000000Z",
    "ttl_minutes": 10
  },
  "plain_text_token": "ik-9xKsecretImpersonationToken..."
}

Wichtig: Der Token ist auf den Mandanten des verwalteten Teams beschränkt. Nutze ihn wie ein reguläres Bearer Token — kein X-Tenant-Id Header erforderlich. Impersonation-Tokens beginnen mit ik- und werden nur einmal angezeigt.

Limits:

  • Maximale TTL: 15 Minuten
  • Maximal 5 aktive (nicht abgelaufene) Impersonation-Tokens pro verwaltetem Team
  • Alle Operationen werden mit der Identität des auslösenden Resellers protokolliert

Impersonation-Token widerrufen ​

DELETE /reseller/managed-teams/{id}/impersonation-tokens/{tokenId}

Antwort (204): Kein Inhalt.

Impersonation-Tokens verwenden ​

Nach dem Erstellen nutzt du den Token wie ein Standard-Bearer-Token:

bash
curl https://app.hoppla.dev/api/v1/monitors \
  -H "Authorization: Bearer ik-9xKsecretImpersonationToken..."

Der Token agiert automatisch im Mandanten-Kontext des verwalteten Teams.


Partner SSO ​

Verwalte die Partner-SSO-Konfiguration verwalteter Teams und erzeuge One-Click-Login-Links. Erfordert den Scope sso:manage.

Partner-SSO-Konfiguration abrufen ​

GET /reseller/managed-teams/{id}/partner-sso

Antwort (200):

json
{
  "data": {
    "enabled": true,
    "has_shared_secret": true,
    "hide_password_login": false,
    "auto_register": true
  }
}

Partner-SSO-Konfiguration aktualisieren ​

PATCH /reseller/managed-teams/{id}/partner-sso

Request Body: Alle Felder sind optional.

FeldTypBeschreibung
enabledbooleanPartner-SSO-Authentifizierung aktivieren/deaktivieren
hide_password_loginbooleanDas E-Mail-/Passwort-Formular auf der Portal-Login-Seite ausblenden. Wenn aktiviert, wird die passwortbasierte Anmeldung zusätzlich serverseitig blockiert — direkte API-Aufrufe an /auth/login und /auth/token liefern für Benutzer dieses Mandanten einen Validierungsfehler.
auto_registerbooleanAutomatisch Konten für neue Benutzer anlegen, die sich per SSO anmelden
auto_link_existing_usersbooleanWer im Team schon ein Konto mit Passwort hat, wird bei der ersten SSO-Anmeldung verknüpft. Standardmäßig aus: Bis du es einschaltest, wird die Anmeldung eines bestehenden Mitglieds abgelehnt. Schalte es nur ein, wenn deine Plattform E-Mail-Adressen prüft

Antwort (200): Gleiche Struktur wie bei GET.

Shared Secret rotieren ​

Erzeugt oder rotiert das Shared Secret, mit dem JWTs signiert werden. Das Klartext-Secret wird nur einmal zurückgegeben.

Nebeneffekt: Das Rotieren des Shared Secret setzt hide_password_login automatisch auf false zurück. Dies ist eine Sicherheitsmaßnahme, um Aussperrungen zu verhindern, falls das neue Secret noch nicht ausgerollt wurde. Aktiviere hide_password_login über den Update-Endpoint erneut, nachdem du bestätigt hast, dass SSO mit dem neuen Secret funktioniert.

POST /reseller/managed-teams/{id}/partner-sso/rotate-secret

Antwort (200):

json
{
  "data": {
    "enabled": true,
    "has_shared_secret": true
  },
  "shared_secret": "a1b2c3d4e5f6..."
}

Wichtig: Kopiere das Secret sofort — es kann nicht erneut abgerufen werden. Verwende es, um auf deiner Plattform HS256-JWTs zu signieren.

Erzeugt eine One-Click-Login-URL für einen Benutzer eines verwalteten Teams. Dies ist der einfachste Weg, SSO bereitzustellen — keine JWT-Signierung auf deiner Seite erforderlich.

POST /reseller/managed-teams/{id}/sso-link

Request Body:

FeldTypPflichtBeschreibung
user_emailemailjaE-Mail des anzumeldenden Benutzers
user_namestringneinName für die automatische Registrierung (falls der Benutzer noch nicht existiert)
redirect_tostringneinPfad, zu dem nach dem Login weitergeleitet wird (z. B. /dashboard/monitors)

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../sso-link \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"user_email": "[email protected]", "user_name": "Alice"}'

Antwort (200):

json
{
  "data": {
    "sso_url": "https://monitoring.acme.com/sso/partner?token=eyJ...&tenant=acme-corp",
    "expires_in_seconds": 300,
    "user_email": "[email protected]",
    "user_exists": true
  }
}

Der Link läuft nach 5 Minuten ab und kann nur einmal verwendet werden (JWT-Replay-Schutz).

Portal-bewusste URLs: Die SSO-URL löst automatisch auf die beste verfügbare Portal-Domain auf:

  1. Wenn das verwaltete Team eine verifizierte eigene Portal-Domain hat, wird diese verwendet (z. B. https://monitoring.acme.com/sso/partner?token=...)
  2. Andernfalls wird, falls der Reseller eine verifizierte Portal-Domain hat, diese verwendet (z. B. https://portal.reseller.com/sso/partner?token=...)
  3. Als Fallback wird https://app.hoppla.dev verwendet

So wird sichergestellt, dass das Session-Cookie auf der richtigen Domain gesetzt wird und Benutzer auf dem Portal angemeldet bleiben, das sie normalerweise nutzen.

Auto-Provisionierung: Ist Partner SSO für das verwaltete Team noch nicht konfiguriert, provisioniert der Aufruf dieses Endpoints es automatisch (erzeugt ein Shared Secret, aktiviert SSO, aktiviert Auto-Register und Account-Verknüpfung). Keine manuelle Einrichtung erforderlich.

Account-Verknüpfung: Hat der Benutzer bereits ein passwortbasiertes Konto, verknüpft der SSO-Link dieses bei der ersten Nutzung automatisch mit Partner SSO.


Feature-Overrides ​

Überschreibe Tarif-Limits für einzelne verwaltete Teams. Ermöglicht Resellern, Features über (oder unter) den Tarif-Standards eines Teams hinaus zu gewähren.

Feature-Overrides abrufen ​

GET /reseller/managed-teams/{id}/feature-overrides

Antwort (200):

json
{
  "data": {
    "plan": "free",
    "overrides": {
      "monitors": 100,
      "lighthouse_audits": true
    },
    "effective_limits": {
      "monitors": 100,
      "status_pages": 1,
      "lighthouse_audits": true,
      "..."
    }
  }
}

Feature-Overrides aktualisieren ​

PUT /reseller/managed-teams/{id}/feature-overrides

Request Body:

json
{
  "overrides": {
    "monitors": 100,
    "lighthouse_audits": true,
    "status_pages": "__remove__"
  }
}

Override-Werte nach Feature-Typ:

FeatureTypWerte
monitorsnumber oder nullAnzahl-Limit oder null für unbegrenzt
status_pagesnumber oder nullAnzahl-Limit oder null für unbegrenzt
team_membersnumber oder nullAnzahl-Limit oder null für unbegrenzt
agent_limitnumberAnzahl der Server-Agents
min_check_intervalnumberMindestintervall in Sekunden
data_retention_daysnumberTage der Datenaufbewahrung
cron_heartbeatsbooleanAktivieren/Deaktivieren
server_monitoringbooleanAktivieren/Deaktivieren
lighthouse_auditsbooleanAktivieren/Deaktivieren
geo_auditsbooleanAktivieren/Deaktivieren
site_crawlsbooleanAktivieren/Deaktivieren
web_vitalsbooleanAktivieren/Deaktivieren
custom_domainsbooleanAktivieren/Deaktivieren
on_call_schedulesbooleanAktivieren/Deaktivieren
api_accessstring"read" oder "full"
notification_channelsarrayErlaubte Kanaltypen, z. B. ["email", "slack", "webhook"]
ai_incident_analysisbooleanKI-Vorfallanalyse aktivieren/deaktivieren
ai_analysis_monthly_limitnumber oder nullKI-Analysen pro Monat (0–10.000) oder null für unbegrenzt
ai_report_monthly_limitnumberKI-Zusammenfassungen des monatlichen PDF-Berichts pro Monat (0–100)
mobile_push_notificationsbooleanMobile Push aktivieren/deaktivieren (nur wenn dein Konto dafür lizenziert ist)
white_label_brandingbooleanDie Admins des Teams dürfen sein Branding selbst setzen. Du kannst deine verwalteten Teams auch ohne das branden

Spezialwerte:

WertBedeutung
nullUnbegrenzt (für numerische Features)
"__remove__"Override entfernen, zurück auf den Tarif-Standard

So wirken Änderungen:

  • Eine Änderung ist partiell: Features, die du weglässt, behalten ihren aktuellen Override. Mit "__remove__" entfernst du einen.
  • Ein Wert geht nie über deine eigene Berechtigung hinaus. Zahlen werden auf dein Limit gesenkt, ein Feature, das du selbst nicht hast, wird als aus gespeichert, Kanäle werden auf deine beschränkt, und null (unbegrenzt) bleibt nur, wenn du selbst unbegrenzt bist.
  • Ein Wert mit falschem Typ wird mit 422 abgelehnt; ein Feature, das nicht in der Tabelle steht, wird ignoriert.
  • Provisioning-Profile und die Standardwerte der Portal-Registrierung nehmen dieselben Features an und folgen denselben Regeln; geprüft wird erneut, wenn daraus ein Team angelegt wird.

Antwort (200): Gleiche Struktur wie bei GET, mit allen Overrides des Teams.


Team-Mitglieder ​

Verwalte Benutzer innerhalb eines verwalteten Teams. Erfordert den Scope members:manage.

Team-Mitglieder auflisten ​

GET /reseller/managed-teams/{id}/members

Antwort (200):

json
{
  "data": [
    {
      "id": "user-uuid-...",
      "name": "Alice Smith",
      "email": "[email protected]",
      "role": "owner",
      "language": "en",
      "mfa_enabled": true,
      "created_at": "2026-01-15T10:00:00.000000Z"
    }
  ]
}

Team-Mitglied anlegen ​

POST /reseller/managed-teams/{id}/members

Request Body:

FeldTypPflichtBeschreibung
emailemailjaE-Mail-Adresse des Benutzers
namestringneinAnzeigename des Benutzers (Standard: E-Mail, wenn weggelassen)
passwordstringjaInitiales Passwort (min. 12 Zeichen, wird gegen Datenleck-Datenbanken geprüft)
rolestringneinmember (Standard) oder admin
languagestringneinen (Standard) oder de

Team-Mitglied aktualisieren ​

Aktualisiert das Profil eines bestehenden Team-Mitglieds. Erfordert den Scope members:manage.

PATCH /reseller/managed-teams/{id}/members/{userId}

Request Body:

FeldTypPflichtBeschreibung
namestringneinAnzeigename des Benutzers (max. 255 Zeichen)
languagestringneinen oder de

Beispiel:

bash
curl -X PATCH https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../members/user-uuid-... \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Alice Johnson", "language": "de"}'

Antwort (200):

json
{
  "data": {
    "id": "user-uuid-...",
    "name": "Alice Johnson",
    "email": "[email protected]",
    "role": "owner",
    "language": "de",
    "mfa_enabled": true,
    "created_at": "2026-01-15T10:00:00.000000Z"
  }
}

Team-Mitglied entfernen ​

DELETE /reseller/managed-teams/{id}/members/{userId}

Antwort (204): Kein Inhalt.

Mitglied löschen (DSGVO Art. 17) ​

Personenbezogene Daten eines Mitglieds in dessen Auftrag löschen. Nicht dasselbe wie Entfernen.

POST /reseller/managed-teams/{id}/members/{userId}/erase

Entfernen nimmt jemanden aus einem Team, eine erneute Einladung ist möglich. Löschen vernichtet die Identität plattformweit — Login, Passkeys, Geräte-Tokens und jedes weitere Team, dem die Person angehört, auch Teams, die du nicht verwaltest. Nicht rückgängig zu machen.

Es gibt keine Bestätigungs-E-Mail an das Mitglied. Für ein verwaltetes Team bist du der Verantwortliche und Hoppla dein Auftragsverarbeiter nach Art. 28; die Weisung liegt bei dir. Statt dessen wird die handelnde Person auf dem Löschauftrag festgehalten, ein Eintrag ins Audit-Log des Teams geschrieben, das Mitglied per E-Mail informiert, und member.erased ausgelöst.

Scope: members:write.

Antwort (202): erasure_id, status: confirmed.

Antwort (422): Das Mitglied ist alleiniger Admin eines Teams, das weitere Mitglieder hat — erst eine andere Person zum Admin machen. Die Sperre verhindert führungslose Teams und gilt unabhängig davon, wem das Team gehört.

Ein verwaltetes Team wird durch eine Löschung nie entfernt, auch dann nicht, wenn die gelöschte Person das letzte Mitglied war.

MFA eines Team-Mitglieds zurücksetzen ​

Entfernt die MFA-Konfiguration eines Team-Mitglieds (nützlich für die Konto-Wiederherstellung).

POST /reseller/managed-teams/{id}/members/{userId}/reset-mfa

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../members/user-uuid-.../reset-mfa \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "message": "MFA has been reset for this user."
}

Team-Einladungen auflisten ​

GET /reseller/managed-teams/{id}/invitations

Antwort (200):

json
{
  "data": [
    {
      "id": "invitation-uuid-...",
      "email": "[email protected]",
      "role": "member",
      "is_pending": true,
      "is_expired": false,
      "expires_at": "2026-03-20T10:00:00.000000Z",
      "accepted_at": null,
      "created_at": "2026-03-13T10:00:00.000000Z"
    }
  ]
}

Team-Einladung erstellen ​

POST /reseller/managed-teams/{id}/invitations

Request Body:

FeldTypPflichtBeschreibung
emailemailjaEinzuladende E-Mail-Adresse
rolestringneinmember (Standard) oder admin

Antwort (201):

json
{
  "data": {
    "id": "invitation-uuid-...",
    "email": "[email protected]",
    "role": "member",
    "is_pending": true,
    "is_expired": false,
    "expires_at": "2026-03-20T10:00:00.000000Z",
    "accepted_at": null,
    "created_at": "2026-03-13T10:00:00.000000Z"
  }
}

Team-Einladung erneut senden ​

Sendet die Einladungs-E-Mail mit einem frischen Token und verlängerter Gültigkeit erneut. Erfordert den Scope members:manage.

POST /reseller/managed-teams/{id}/invitations/{invitationId}/resend

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../invitations/invitation-uuid-.../resend \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "id": "invitation-uuid-...",
    "email": "[email protected]",
    "role": "member",
    "is_pending": true,
    "is_expired": false,
    "expires_at": "2026-03-22T10:00:00.000000Z",
    "accepted_at": null,
    "created_at": "2026-03-13T10:00:00.000000Z"
  }
}

Team-Einladung widerrufen ​

DELETE /reseller/managed-teams/{id}/invitations/{invitationId}

Monatliche Team-Berichte ​

Verwalte die Einstellungen für monatliche Berichte eines verwalteten Teams. Erfordert den Scope teams:read / teams:write.

Monatliche Berichte sind für alle Mandanten standardmäßig aktiviert. Reseller können sie deaktivieren oder pro verwaltetem Team eigene Empfänger konfigurieren.

Konfiguration der monatlichen Berichte abrufen ​

GET /reseller/managed-teams/{managedTeam}/monthly-report

Antwort (200):

json
{
  "data": {
    "enabled": true,
    "recipients": ["[email protected]"],
    "last_sent_at": "2026-04-01T06:00:00Z",
    "ai_summary": false,
    "ai_summary_available": true
  }
}

ai_summary_available ist true, wenn der Tarif des Teams (oder dein Override von ai_report_monthly_limit) KI-Zusammenfassungen enthält.

Konfiguration der monatlichen Berichte aktualisieren ​

PATCH /reseller/managed-teams/{managedTeam}/monthly-report

Request Body:

FeldTypPflichtBeschreibung
enabledbooleanjaMonatliche Berichte aktivieren oder deaktivieren
recipientsarrayjaE-Mail-Adressen, die den Bericht erhalten (max. 10). Leeres Array = an den Team-Admin gesendet.
ai_summarybooleanneinDie Texte der Zusammenfassung im PDF-Bericht mit KI-Unterstützung formulieren. Weggelassen bleibt der gespeicherte Wert. true wird mit 422 abgelehnt, wenn der Tarif des Teams es nicht enthält.

Beispiel:

bash
curl -X PATCH "https://app.hoppla.dev/api/v1/reseller/managed-teams/{id}/monthly-report" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enabled": true, "recipients": ["[email protected]", "[email protected]"]}'

Monatsbericht als PDF herunterladen ​

GET /reseller/managed-teams/{managedTeam}/reports/monthly/pdf?month=YYYY-MM

Erfordert den Scope monitors:read. Liefert application/pdf: den Monatsbericht des Teams in deinem Branding, ohne etwas von Hoppla. month ist standardmäßig der vorige Monat; der laufende Monat liefert den Bericht bis heute, die letzten 13 Monate sind abrufbar. 503 mit Retry-After-Header heißt, dass das PDF gerade nicht erstellt werden kann. Dasselbe PDF hängt an der monatlichen E-Mail.


Team-API-Keys ​

Verwalte API-Keys für ein verwaltetes Team. Erfordert den Scope api-keys:manage.

Team-API-Keys auflisten ​

GET /reseller/managed-teams/{id}/api-keys

Antwort (200):

json
{
  "data": [
    {
      "id": "key-uuid-...",
      "name": "CI Integration",
      "scopes": ["read", "write"],
      "last_used_at": "2026-03-10T14:00:00.000000Z",
      "expires_at": "2026-12-31T23:59:59.000000Z",
      "created_at": "2026-03-01T10:00:00.000000Z"
    }
  ]
}

Team-API-Key erstellen ​

POST /reseller/managed-teams/{id}/api-keys

Request Body:

FeldTypPflichtBeschreibung
namestringjaKey-Name
scopesarrayneinDie Scopes eines Kunden-API-Keys: granular <bereich>:read, :write oder :manage (zum Beispiel ["monitors:read", "incidents:manage"], siehe Scopes), oder das ältere ["read"] / ["read", "write"]. Standard ["read", "write"]. Erlaubt der Tarif des Teams nur lesenden API-Zugriff, bleiben nur die Lese-Scopes
expires_atdatetimeneinAblaufdatum (ISO 8601, muss in der Zukunft liegen). Weglassen für keinen Ablauf

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../api-keys \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CI Integration",
    "scopes": ["read", "write"],
    "expires_at": "2026-12-31T23:59:59Z"
  }'

Antwort (201):

json
{
  "data": {
    "id": "key-uuid-...",
    "name": "CI Integration",
    "scopes": ["read", "write"],
    "last_used_at": null,
    "expires_at": "2026-12-31T23:59:59.000000Z",
    "created_at": "2026-03-10T10:00:00.000000Z"
  },
  "plain_text_token": "svc-secretServiceApiKeyValue..."
}

Wichtig: Das plain_text_token wird nur einmal zurückgegeben. Bewahre es sicher auf. Service-API-Keys verwalteter Teams beginnen mit svc- und gewähren Zugriff ausschließlich auf dieses eine Team.

Team-API-Key widerrufen ​

DELETE /reseller/managed-teams/{id}/api-keys/{keyId}

Branding verwalteter Teams ​

Verwalte die Branding-Einstellungen eines bestimmten verwalteten Teams. Erfordert den Scope branding:manage sowie das Tarif-Feature white_label_branding.

Branding eines verwalteten Teams abrufen ​

GET /reseller/managed-teams/{id}/branding

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../branding \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "brand_name": "Acme Monitoring",
    "alert_prefix": "Acme Alert!",
    "logo_url": "https://example.com/logo.png",
    "logo_url_dark": "https://example.com/logo-dark.png",
    "symbol_url": "https://example.com/symbol.png",
    "primary_color": "#6366F1",
    "secondary_color": "#8B5CF6",
    "favicon_url": "https://example.com/favicon.ico",
    "footer_text": "Sent by Acme Monitoring",
    "footer_url": "https://acme-monitoring.com",
    "privacy_url": "https://acme-monitoring.com/privacy",
    "imprint_url": "https://acme-monitoring.com/imprint",
    "upgrade_url": "https://acme-monitoring.com/upgrade",
    "support_url": "https://acme-monitoring.com/support",
    "hide_powered_by": true,
    "notification_from_name": "Acme Alerts"
  }
}

Branding eines verwalteten Teams aktualisieren ​

PATCH /reseller/managed-teams/{id}/branding

Request Body: Alle Felder sind optional. Nur die mitgeschickten Felder werden aktualisiert. Gleiche Felder wie beim Branding-Endpoint des eigenen Mandanten (siehe Abschnitt Branding), inklusive upgrade_url und support_url.

Antwort (200): Gleiche Struktur wie bei GET.


Portal-Custom-Domain ​

Konfiguriere eine Custom Domain für das Portal eines verwalteten Teams. Erfordert den Scope portal:manage.

Portal-Domain abrufen ​

GET /reseller/managed-teams/{id}/portal-domain

Antwort (200):

json
{
  "data": {
    "domain": "monitoring.acme.com",
    "verified": true,
    "verified_at": "2026-03-05T12:00:00.000000Z",
    "cname_target": "cname.status.hoppla.dev"
  }
}

Portal-Domain setzen ​

PUT /reseller/managed-teams/{id}/portal-domain

Request Body:

FeldTypPflichtBeschreibung
domainstringjaCustom Domain (z. B. monitoring.acme.com)

Lege nach dem Setzen einen CNAME-DNS-Eintrag an, der die Domain auf cname.status.hoppla.dev zeigen lässt, und verifiziere sie anschließend.

Portal-Domain-DNS verifizieren ​

POST /reseller/managed-teams/{id}/portal-domain/verify

Prüft, ob der CNAME-Eintrag korrekt konfiguriert ist.

Portal-Domain entfernen ​

DELETE /reseller/managed-teams/{id}/portal-domain

Portal-Domain des Reseller-Kontos ​

Konfiguriere eine eigene Portal-Custom-Domain für das eigene Konto des Resellers. Erfordert den Scope portal:manage. Diese Domain wird als Fallback-Portal-URL für alle verwalteten Teams verwendet, die keine eigene Custom Domain haben.

Reseller-Portal-Domain abrufen ​

GET /reseller/portal-domain

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/reseller/portal-domain \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "domain": "portal.reseller.com",
    "verified": true,
    "verified_at": "2026-03-01T10:00:00.000000Z",
    "cname_target": "cname.status.hoppla.dev"
  }
}

Reseller-Portal-Domain setzen ​

PUT /reseller/portal-domain

Request Body:

FeldTypPflichtBeschreibung
domainstringjaCustom Domain (z. B. portal.reseller.com)

Lege nach dem Setzen einen CNAME-DNS-Eintrag an, der die Domain auf cname.status.hoppla.dev zeigen lässt, und verifiziere sie anschließend.

Reseller-Portal-Domain-DNS verifizieren ​

POST /reseller/portal-domain/verify

Prüft, ob der CNAME-Eintrag korrekt konfiguriert ist.

Reseller-Portal-Domain entfernen ​

DELETE /reseller/portal-domain

Antwort (204): Kein Inhalt.


Portal-Registrierungseinstellungen ​

Konfiguriere die Self-Service-Registrierung auf deinem Portal. Wenn aktiviert, können sich neue Benutzer direkt auf deiner Portal-Domain registrieren und werden automatisch als verwaltete Teams provisioniert. Erfordert den Scope portal:manage.

Portal-Einstellungen abrufen ​

GET /reseller/portal-settings

Antwort (200):

json
{
  "data": {
    "portal_allow_registration": true,
    "portal_registration_defaults": {
      "plan": "starter",
      "trial_days": 14,
      "trial_plan": "pro",
      "feature_overrides": {
        "monitors": 25,
        "lighthouse_audits": true
      }
    }
  }
}

Portal-Einstellungen aktualisieren ​

PATCH /reseller/portal-settings

Request Body: Alle Felder sind optional.

FeldTypBeschreibung
portal_allow_registrationbooleanSelf-Service-Registrierung aktivieren/deaktivieren
portal_registration_defaults.planstringStandard-Tarif für Neuregistrierungen: free, hobby, starter oder pro
portal_registration_defaults.trial_daysinteger|nullTestphase (1–365 Tage). null zum Deaktivieren der Testphase
portal_registration_defaults.trial_planstring|nullTarif während der Testphase. null, um den Standard-Tarif zu verwenden
portal_registration_defaults.feature_overridesobject|nullStandard-Feature-Overrides (gleiche Felder wie unter Feature-Overrides)

Beispiel:

bash
curl -X PATCH https://app.hoppla.dev/api/v1/reseller/portal-settings \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "portal_allow_registration": true,
    "portal_registration_defaults": {
      "plan": "starter",
      "trial_days": 14,
      "trial_plan": "pro",
      "feature_overrides": {
        "monitors": 50,
        "lighthouse_audits": true,
        "geo_audits": true
      }
    }
  }'

Antwort (200): Gleiche Struktur wie bei GET.


E-Mail-Unterdrückung ​

Steuere, welche Plattform-E-Mails an die Benutzer deiner verwalteten Teams gesendet werden. Wird ein E-Mail-Typ unterdrückt, feuert Hoppla stattdessen einen email.*-Webhook, sodass du die E-Mail selbst versenden kannst. Payload-Details findest du unter Webhooks — E-Mail-Unterdrückung.

E-Mail-Unterdrückungs-Konfiguration abrufen ​

GET /reseller/email-suppression

Antwort (200):

json
{
  "data": {
    "suppressed_types": ["password_reset", "invitation"],
    "available_types": [
      { "key": "password_reset", "category": "auth", "description": "Password reset link" },
      { "key": "email_change_verify", "category": "auth", "description": "Email change verification link" },
      { "key": "email_changed_notify", "category": "auth", "description": "Email change notification to old address" },
      { "key": "invitation", "category": "team", "description": "Team member invitation" },
      { "key": "member_removed", "category": "team", "description": "Member removal notification" },
      { "key": "trial_ending", "category": "billing", "description": "Trial expiration reminder" },
      { "key": "trial_expired", "category": "billing", "description": "Trial expired notification" },
      { "key": "incident_created", "category": "monitoring", "description": "Incident alert email" },
      { "key": "incident_resolved", "category": "monitoring", "description": "Incident recovery email" },
      { "key": "warning", "category": "monitoring", "description": "Warning notification email" },
      { "key": "dns_changed", "category": "monitoring", "description": "DNS records changed notification" },
      { "key": "certificate_renewed", "category": "monitoring", "description": "Certificate renewed notification" },
      { "key": "digest", "category": "monitoring", "description": "Batched notification digest email" }
    ]
  }
}

E-Mail-Unterdrückungs-Konfiguration aktualisieren ​

PUT /reseller/email-suppression

Request Body:

FeldTypPflichtBeschreibung
suppressed_typesstring[]jaArray der zu unterdrückenden E-Mail-Typ-Schlüssel (siehe verfügbare Typen oben)

Beispiel:

bash
curl -X PUT https://app.hoppla.dev/api/v1/reseller/email-suppression \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "suppressed_types": [
      "password_reset",
      "invitation",
      "member_removed",
      "incident_created",
      "warning"
    ]
  }'

Antwort (200): Gleiche Struktur wie bei GET.

Wichtig: Stelle sicher, dass du einen Webhook-Benachrichtigungskanal für die entsprechenden email.*-Event-Typen abonniert hast, bevor du die Unterdrückung aktivierst. Andernfalls werden unterdrückte E-Mails stillschweigend verworfen.


Mandantenübergreifende Übersicht & Abfragen ​

Aggregierte Sichten über alle deine verwalteten Mandanten in einem einzigen Aufruf. Kein X-Tenant-Id-Header nötig — diese Endpoints umspannen automatisch alle Teams, die du verwaltest.

Übersicht ​

Zustands-Snapshot über alle verwalteten Mandanten abrufen.

GET /reseller/overview

Scope: teams:read

Antwort (200):

json
{
  "data": {
    "tenants": {
      "total": 487,
      "active": 450,
      "paused": 12,
      "trial": 25,
      "trial_expiring_7d": 8
    },
    "monitors": {
      "total": 4521,
      "up": 4380,
      "down": 23,
      "warning": 45,
      "paused": 73
    },
    "incidents": {
      "active": 18,
      "critical": 3,
      "major": 7,
      "minor": 8
    },
    "ssl_expiring_14d": 12
  }
}

Monitore mandantenübergreifend auflisten ​

GET /reseller/monitors

Scope: teams:read

ParameterTypBeschreibung
tenant_iduuidAuf ein verwaltetes Team filtern
statusstringup, down, warning, paused
is_enabledboolNach aktiviertem Zustand filtern
searchstringNach Name oder URL suchen
tagstringNach Tag filtern
typestringMonitor-Typ (http, ping, tcp)
sortstringname, status, created_at, url
sort_dirstringasc, desc
per_pageintMax. 250

Antwort (200): Paginierte Liste von Monitoren mit tenant_name, status, uptime_30d, avg_response_ms und checks-Array.

Vorfälle mandantenübergreifend auflisten ​

GET /reseller/incidents

Scope: teams:read

ParameterTypBeschreibung
tenant_iduuidAuf ein verwaltetes Team filtern
statusstringinvestigating, identified, monitoring, resolved
severitystringKommagetrennt: critical,major
acknowledgedboolNach Bestätigung filtern
sincedatetimeNur Vorfälle nach diesem Zeitpunkt
sortstringstarted_at, severity, updated_at
per_pageintMax. 250

Mandantenübergreifender Bericht ​

Monatliche Zusammenfassung pro Mandant über Monitore, Uptime und Vorfälle.

GET /reseller/report

Scope: teams:read

ParameterTypBeschreibung
periodstringYYYY-MM (Standard: aktueller Monat)
tenant_idsstringKommagetrennte UUIDs zum Filtern

Mandantenübergreifende DNS-Historie ​

Zonen-bewusste DNS-Historie für einen einzelnen Monitor in einem verwalteten Team — liefert den Zonen-Apex, die autoritativen Nameserver, bestätigte Record-Änderungen und die resolver-übergreifende Propagation, ohne ein Impersonation-Token zu erzeugen. Der Endpoint ist auf ein Team beschränkt, das dir gehört, und liest die DNS-Daten des verwalteten Mandanten direkt.

GET /reseller/managed-teams/{managedTeam}/monitors/{monitorId}/dns-history

Scope: teams:read

Antwort (200):

json
{
  "data": {
    "monitor_id": "monitor-uuid-...",
    "records": [
      { "type": "A", "name": "acmecorp.com", "value": "203.0.113.10", "ttl": 300 }
    ],
    "zone": "acmecorp.com",
    "nameservers": ["ns1.acme-dns.com", "ns2.acme-dns.com"],
    "authoritative": true,
    "changes": [
      {
        "detected_at": "2026-01-15T16:00:00.000000Z",
        "changes": [
          { "type": "NS", "old": ["ns1.old-dns.com"], "new": ["ns1.acme-dns.com", "ns2.acme-dns.com"] }
        ]
      }
    ],
    "propagation": {
      "consistent": true,
      "resolvers": []
    }
  }
}

Hat der Monitor keinen DNS-Check, sind records, changes und nameservers leer und zone / authoritative / propagation sind null.


Reseller-Webhooks ​

Komfort-Endpoints zur Verwaltung von Webhook-Abonnements für Reseller-Events. Erstellen sowohl einen Benachrichtigungskanal als auch eine Regel in einem einzigen Aufruf.

Event-Typen auflisten ​

GET /reseller/webhook-event-types

Scope: webhooks:read

Liefert alle abonnierbaren Event-Typen, nach Kategorie gruppiert.

Webhook erstellen ​

POST /reseller/webhooks

Scope: webhooks:write

Request:

json
{
  "name": "Ops Integration",
  "url": "https://hooks.example.com/hoppla",
  "secret": "whsec_...",
  "events": ["incident.created", "incident.resolved", "monitor.down", "ssl.expiring"],
  "tenant_filter": {
    "tenant_ids": ["uuid1", "uuid2"],
    "labels": ["prod-*"]
  }
}

Der tenant_filter ist optional — lass ihn weg, um Events von allen verwalteten Mandanten zu empfangen. Nutze tenant_ids für exakte Treffer oder labels mit nachgestellten Wildcards für Mustervergleiche.

Webhooks auflisten / anzeigen / aktualisieren / löschen ​

GET    /reseller/webhooks                  # Scope: webhooks:read
GET    /reseller/webhooks/{id}              # Scope: webhooks:read
PATCH  /reseller/webhooks/{id}              # Scope: webhooks:write
DELETE /reseller/webhooks/{id}              # Scope: webhooks:write

Zustellungsprotokolle ​

GET /reseller/webhooks/{id}/deliveries

Scope: webhooks:read

Liefert die letzten 50 Zustellversuche mit Status und Fehlermeldungen.


Batch-Operationen ​

Hochdurchsatz-Endpoints zur Verwaltung von Monitoren, Checks und Vorfällen über verwaltete Teams hinweg.

Monitore im Batch erstellen ​

Bis zu 100 Monitore in einem einzigen Aufruf erstellen.

POST /reseller/managed-teams/{managedTeam}/monitors/batch

Scope: teams:write

Request:

json
{
  "monitors": [
    {
      "name": "Customer Website",
      "url": "https://customer.com",
      "type": "http",
      "check_interval": 60,
      "tags": ["web", "production"],
      "checks": [
        { "type": "uptime" },
        { "type": "ssl" },
        { "type": "dns", "settings": { "record_types": ["A", "AAAA", "NS", "CAA"] } }
      ]
    }
  ]
}

Wird checks weggelassen, werden je nach Monitor-Typ Standard-Checks erstellt. Liefert { created: [...], errors: [...] } mit Unterstützung für Teilerfolge.

Für dns-Checks ist settings.record_types ein optionales Array, beschränkt auf A, AAAA, MX, CNAME, NS, TXT, SOA, SRV, CAA. Es wird identisch zum kundenseitigen Monitor-Schreibpfad validiert, sodass ein Reseller-Token keine Record-Typen speichern kann, die der Kunden-Validator ablehnen würde.

Monitore im Batch aktualisieren ​

PATCH /reseller/managed-teams/{managedTeam}/monitors/batch
json
{
  "updates": [
    { "id": "uuid1", "changes": { "check_interval": 120 } },
    { "id": "uuid2", "changes": { "is_enabled": false } }
  ]
}

Monitore im Batch löschen ​

DELETE /reseller/managed-teams/{managedTeam}/monitors/batch
json
{ "monitor_ids": ["uuid1", "uuid2"] }

Check-Aktionen im Batch ​

Bis zu 200 Checks in einem Aufruf aktivieren, deaktivieren oder pausieren (snooze).

POST /reseller/managed-teams/{managedTeam}/checks/batch
json
{
  "actions": [
    { "check_id": "uuid1", "action": "disable" },
    { "check_id": "uuid2", "action": "snooze", "duration": "24h" }
  ]
}

Dauern: 1h, 4h, 8h, 24h, 48h, 7d.

Vorfälle im Batch bestätigen ​

Vorfälle über alle verwalteten Mandanten hinweg bestätigen.

POST /reseller/incidents/batch-acknowledge
json
{ "incident_ids": ["uuid1", "uuid2"] }

Statistiken im Batch abfragen ​

Uptime und Antwortzeit für bis zu 200 Monitore in einem Aufruf abrufen.

POST /monitors/stats-batch
json
{ "monitor_ids": ["uuid1", "uuid2"] }

Liefert pro Monitor uptime_30d und avg_response_ms.


Monitor-Templates ​

Wiederverwendbare Monitor-Konfigurationen mit Variablen-Substitution.

CRUD ​

GET    /reseller/monitor-templates
POST   /reseller/monitor-templates
GET    /reseller/monitor-templates/{id}
PATCH  /reseller/monitor-templates/{id}
DELETE /reseller/monitor-templates/{id}

Beispiel zum Erstellen:

json
{
  "name": "WordPress Standard",
  "monitors": [
    {
      "name_template": "{{domain}} Website",
      "url_template": "https://{{domain}}/",
      "type": "http",
      "check_interval": 60,
      "tags": ["{{plan}}"],
      "checks": [
        { "type": "uptime" },
        { "type": "ssl" },
        { "type": "dns", "settings": { "record_types": ["A", "AAAA", "NS", "CAA"] } },
        { "type": "security_headers" }
      ]
    }
  ],
  "variables": [
    { "name": "domain", "required": true, "description": "Customer domain" },
    { "name": "plan", "required": false, "default": "standard" }
  ]
}

Wie bei der Batch-Erstellung ist settings.record_types eines dns-Checks ein optionales Array, beschränkt auf A, AAAA, MX, CNAME, NS, TXT, SOA, SRV, CAA, und wird identisch zum Kunden-Schreibpfad validiert.

Template anwenden ​

POST /reseller/managed-teams/{managedTeam}/apply-template
json
{
  "template_id": "uuid",
  "variables": { "domain": "customer.com" }
}

Erstellt alle im Template definierten Monitore mit eingesetzten Variablen.


Provisionierungsprofile ​

Vorkonfigurierte Profile zur Mandanten-Einrichtung für die Provisionierung in einem Aufruf.

GET    /reseller/provisioning-profiles
POST   /reseller/provisioning-profiles
GET    /reseller/provisioning-profiles/{id}
PATCH  /reseller/provisioning-profiles/{id}
DELETE /reseller/provisioning-profiles/{id}

Beispiel zum Erstellen:

json
{
  "name": "WordPress Hosting Standard",
  "plan": "pro",
  "trial_days": 14,
  "feature_overrides": { "monitors": 50, "min_check_interval": 60 },
  "branding": { "brand_name": "CustomerCo Monitoring" },
  "monitor_template_id": "template-uuid"
}

Monitor-Berichte ​

Tägliche Uptime-Aufschlüsselung für einen Monitor über einen Zeitraum.

GET /monitors/{monitor}/report?from=2026-03-01&to=2026-04-01

Liefert täglich uptime_pct, avg_response_ms, total_checks sowie das gesamte uptime_pct und die Anzahl incidents. Maximaler Zeitraum: 90 Tage.


Erweiterte Filterung ​

Alle Listen-Endpoints unterstützen jetzt erweiterte Filterung und Sortierung.

Monitore (GET /monitors) ​

ParameterTypBeschreibung
is_enabledboolNach aktiviertem Zustand filtern
statusstringup, down, warning, paused, maintenance
check_typestringNur Monitore mit diesem Check-Typ
sortstringname, created_at, url, check_interval
sort_dirstringasc, desc
created_afterdateErstellt nach diesem Datum
created_beforedateErstellt vor diesem Datum

Vorfälle (GET /incidents) ​

ParameterTypBeschreibung
severitystringKommagetrennt: critical,major,minor
check_typestringNach ursprünglichem Check-Typ filtern
acknowledgedboolNach Bestätigungsstatus filtern
snoozedboolNach Snooze-Status filtern
sincedatetimeNur Vorfälle nach diesem Zeitpunkt
sortstringstarted_at, severity, updated_at, resolved_at

Verwaltete Teams (GET /reseller/managed-teams) ​

ParameterTypBeschreibung
searchstringNach Team-Name oder Label suchen
planstringKommagetrennter Tarif-Filter
statusstringactive, paused, trial
has_incidentsboolNur Teams mit aktiven Vorfällen
trial_expires_beforedateNach Ende der Testphase filtern
sortstringname, created_at, monitors_count
per_pageintMax. 250 (Reseller-Endpoints)

Verwaltungs-Endpoints pro Team ​

Neben dem Impersonation-Header X-Tenant-Id bietet Hoppla dedizierte Reseller-Endpoints zur Verwaltung der Ressourcen eines bestimmten Teams direkt unter /reseller/managed-teams/{id}/…. Das ist der empfohlene Weg für die Automatisierung: Er ist Scope-gebunden (jede Familie ist einer Scope-Domäne wie monitors:write oder notifications:manage zugeordnet) und jede Aktion wird auditiert -- ganz ohne Mandanten-Kontext-Header.

Folgende Ressourcen-Familien pro Team stehen unter /reseller/managed-teams/{id}/ zur Verfügung:

RessourceEndpointsScope-Domäne
BenachrichtigungskanäleGET/POST .../notification-channels, GET/PATCH/DELETE .../notification-channels/{cid}notifications
BenachrichtigungsregelnGET/POST .../notification-rules, GET/PATCH/DELETE .../notification-rules/{rid}notifications
EskalationsrichtlinienGET/POST .../escalation-policies, GET/PATCH/DELETE .../escalation-policies/{eid}notifications
Bereitschaftspläne (On-Call)GET/POST .../on-call-schedules, GET/PATCH/DELETE .../on-call-schedules/{sid}notifications
WartungsfensterGET/POST .../maintenance-windows, GET/PATCH/DELETE .../maintenance-windows/{mid}maintenance
StatusseitenGET/POST .../status-pages, GET/PATCH/DELETE .../status-pages/{spid}status-pages
MonitoreGET/POST .../monitors, GET/PATCH/DELETE .../monitors/{mid}monitors
Monitor-Checks.../monitors/{mid}/checks sowie die Aktionen enable, disable, request-run, snooze und timeseriesmonitors
VorfälleGET .../incidents, Aktualisieren/Schließenincidents
Bericht (PDF)GET .../report.pdfteams / monitors

Jeder Aufruf erfordert ein Reseller-Token (rk-…) mit dem passenden Scope. Nutze diese Endpoints statt der X-Tenant-Id-Impersonation, wenn du Scope-begrenzten, auditierten Zugriff auf die Ressourcen eines einzelnen Teams möchtest.

Mandantenübergreifende Operationen ​

Um Aktionen im Kontext eines verwalteten Teams auszuführen, hängst du den X-Tenant-Id Header an jeden Standard-API-Endpoint an. Alle Details findest du unter Impersonation. (Für Scope-begrenzte, auditierte Automatisierung pro Team verwende bevorzugt die Verwaltungs-Endpoints pro Team oben.)

Beispiel: Monitore eines verwalteten Teams auflisten:

bash
curl https://app.hoppla.dev/api/v1/monitors \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Tenant-Id: managed-tenant-uuid-..."

Beispiel: Monitor in einem verwalteten Team erstellen:

bash
curl -X POST https://app.hoppla.dev/api/v1/monitors \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Tenant-Id: managed-tenant-uuid-..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Website",
    "url": "https://acmecorp.com",
    "type": "uptime",
    "interval": 60,
    "is_enabled": true
  }'

Wenn X-Tenant-Id gesetzt ist, beziehen sich alle API-Antworten auf den Ziel-Mandanten. Datenisolierung wird auf Infrastrukturebene erzwungen.

Beispiel: Einen Check in einem verwalteten Team pausieren (snooze):

bash
curl -X POST https://app.hoppla.dev/api/v1/checks/{check-id}/snooze \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Tenant-Id: managed-tenant-uuid-..." \
  -H "Content-Type: application/json" \
  -d '{"minutes": 60}'

Beispiel: Pause (Snooze) eines Checks in einem verwalteten Team aufheben:

bash
curl -X POST https://app.hoppla.dev/api/v1/checks/{check-id}/unsnooze \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Tenant-Id: managed-tenant-uuid-..."

Beispiel: Audit-Log eines verwalteten Teams anzeigen:

bash
curl "https://app.hoppla.dev/api/v1/audit-log?action=check_snoozed,check_unsnoozed" \
  -H "Authorization: Bearer $TOKEN" \
  -H "X-Tenant-Id: managed-tenant-uuid-..."

Uptime-Badges ​

Uptime-Badges sind öffentliche Endpoints, die keine Authentifizierung und keinen X-Tenant-Id-Header benötigen — nur die Monitor-UUID:

bash
# Default badge (shields.io style)
curl https://app.hoppla.dev/api/badges/{monitor-uuid}

# Small badge (dot + percentage)
curl https://app.hoppla.dev/api/badges/{monitor-uuid}/small

# Custom colors for dark mode embedding
curl "https://app.hoppla.dev/api/badges/{monitor-uuid}?label_color=2d333b&style=flat"

Badge-URLs funktionieren auch auf Custom Domains von Reseller-Portalen — der Pfad /api/badges/* wird auch auf deiner Portal-Domain ausgeliefert.


Benachrichtigungskanäle ​

Richte Benachrichtigungskanäle ein, um Webhook-Events zu empfangen. Kanäle erstellst du im Kontext deines eigenen Mandanten (ohne X-Tenant-Id).

Unterstützte Kanaltypen ​

TypKonfigurationsfelder
webhookurl (Pflicht), secret (optional, für HMAC-Signierung)
emailrecipients (Array von E-Mail-Adressen)
slackwebhook_url
discordwebhook_url
microsoft_teamswebhook_url
pagerdutyrouting_key
telegrambot_token, chat_id

Webhook-Kanal erstellen ​

bash
curl -X POST https://app.hoppla.dev/api/v1/notification-channels \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Provisioning Webhooks",
    "type": "webhook",
    "config": {
      "url": "https://your-server.com/hoppla-webhook",
      "secret": "your-hmac-secret"
    },
    "is_enabled": true
  }'

Benachrichtigungsregel erstellen ​

Abonniere Reseller-Events:

bash
curl -X POST https://app.hoppla.dev/api/v1/notification-rules \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "channel_id": "channel-uuid-...",
    "event_types": ["team.provisioned", "team.deleted", "monitor.created", "monitor.deleted"],
    "monitor_filter": {}
  }'

Alle Details zu Payloads und Zustellung findest du unter Webhooks.


Branding ​

Passe an, wie Benachrichtigungen und E-Mails den Benutzern deiner verwalteten Teams erscheinen. Nur für Mandanten mit dem Tarif-Feature white_label_branding verfügbar.

Branding abrufen ​

GET /branding

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/branding \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "brand_name": "Acme Monitoring",
    "alert_prefix": "Acme Alert!",
    "logo_url": "https://example.com/logo.png",
    "logo_url_dark": "https://example.com/logo-dark.png",
    "symbol_url": "https://example.com/symbol.png",
    "primary_color": "#6366F1",
    "secondary_color": "#8B5CF6",
    "favicon_url": "https://example.com/favicon.ico",
    "footer_text": "Sent by Acme Monitoring",
    "footer_url": "https://acme-monitoring.com",
    "privacy_url": "https://acme-monitoring.com/privacy",
    "imprint_url": "https://acme-monitoring.com/imprint",
    "upgrade_url": "https://acme-monitoring.com/upgrade",
    "support_url": "https://acme-monitoring.com/support",
    "hide_powered_by": true,
    "notification_from_name": "Acme Alerts"
  }
}

Branding aktualisieren ​

PATCH /branding

Request Body: Alle Felder sind optional. Nur die mitgeschickten Felder werden aktualisiert.

FeldTypBeschreibung
brand_namestringMarkenname, der in Benachrichtigungen und E-Mails angezeigt wird (max. 100)
alert_prefixstringBenachrichtigungs-Präfix, z. B. "Acme Alert!" (max. 50)
logo_urlurlLogo für helle Hintergründe (max. 500, SSRF-validiert)
logo_url_darkurlLogo für dunkle Hintergründe / E-Mail-Header (max. 500, SSRF-validiert)
symbol_urlurlQuadratisches App-Symbol für die eingeklappte Seitenleiste und die Portal-Anmeldung, mindestens 64 × 64 px (max. 500, SSRF-validiert). Nicht gesetzt: das Favicon, sonst der erste Buchstabe des Markennamens
primary_colorstringHex-Farbcode, z. B. #6366F1
secondary_colorstringHex-Farbcode für sekundäre Elemente
favicon_urlurlFavicon-URL (max. 500, SSRF-validiert)
footer_textstringE-Mail-Footer-Text (max. 200)
footer_urlurlE-Mail-Footer-Link-URL (max. 500, SSRF-validiert)
privacy_urlurlDatenschutz-Link im E-Mail-Footer (max. 500, SSRF-validiert)
imprint_urlurlImpressum-/Rechtliches-Link im E-Mail-Footer (max. 500, SSRF-validiert)
upgrade_urlurlUpgrade-/Upsell-Link-URL (max. 500, SSRF-validiert)
support_urlurlSupport-Seiten-Link-URL (max. 500, SSRF-validiert)
hide_powered_byboolean"Powered by Hoppla"-Hinweis entfernen (erfordert das Tarif-Feature white_label_branding)
notification_from_namestringEigener "From"-Name für Benachrichtigungs-E-Mails (max. 100)

Beispiel:

bash
curl -X PATCH https://app.hoppla.dev/api/v1/branding \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "brand_name": "Acme Monitoring",
    "alert_prefix": "Acme Alert!",
    "primary_color": "#2563EB",
    "footer_text": "Sent by Acme Monitoring",
    "hide_powered_by": true
  }'

Antwort (200): Gleiche Struktur wie bei GET.

Hinweis: Das Feld hide_powered_by erfordert das Tarif-Feature white_label_branding. Es ohne dieses Feature auf true zu setzen, liefert 403 Forbidden.

Verwaltete Teams: Nutze GET/PATCH /reseller/managed-teams/{id}/branding, um das Branding eines bestimmten verwalteten Teams zu verwalten (erfordert den Scope branding:manage).


Custom-SMTP-Konfiguration ​

Versende Benachrichtigungs-E-Mails von deiner eigenen Domain. Erfordert das Tarif-Feature custom_smtp (Reseller-Tarif).

SMTP-Konfiguration abrufen ​

GET /smtp-config

Beispiel:

bash
curl https://app.hoppla.dev/api/v1/smtp-config \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "data": {
    "host": "smtp.example.com",
    "port": 587,
    "encryption": "tls",
    "username": "[email protected]",
    "password": "********",
    "from_address": "[email protected]",
    "from_name": "Acme Alerts"
  }
}

Das Passwort wird immer als ******** zurückgegeben. Wenn du beim Aktualisieren ******** zurücksendest, bleibt das bestehende Passwort erhalten.

Liefert {"data": null}, wenn keine SMTP-Konfiguration gesetzt ist (E-Mails werden über den Plattform-Standard versendet).

SMTP-Konfiguration aktualisieren ​

PATCH /smtp-config

Request Body:

FeldTypPflichtBeschreibung
hoststringjaSMTP-Server-Hostname
portintegerjaPort: 25, 465, 587 oder 2525
encryptionstringjatls oder ssl
usernamestringneinSMTP-Benutzername
passwordstringneinSMTP-Passwort (******** senden, um das bestehende zu behalten)
from_addressemailneinAbsender-E-Mail-Adresse
from_namestringneinAnzeigename des Absenders

Beispiel:

bash
curl -X PATCH https://app.hoppla.dev/api/v1/smtp-config \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "host": "smtp.example.com",
    "port": 587,
    "encryption": "tls",
    "username": "[email protected]",
    "password": "your-smtp-password",
    "from_address": "[email protected]",
    "from_name": "Acme Alerts"
  }'

Antwort (200): Gleiche Struktur wie bei GET.

SMTP-Verbindung testen ​

POST /smtp-config/test

Auf 5 Anfragen pro Minute begrenzt.

Beispiel:

bash
curl -X POST https://app.hoppla.dev/api/v1/smtp-config/test \
  -H "Authorization: Bearer $TOKEN"

Antwort (200):

json
{
  "success": true
}

SMTP-Konfiguration entfernen ​

DELETE /smtp-config

Entfernt die Custom-SMTP-Konfiguration. E-Mails werden über den Plattform-Standard versendet.

Beispiel:

bash
curl -X DELETE https://app.hoppla.dev/api/v1/smtp-config \
  -H "Authorization: Bearer $TOKEN"

Antwort (204): Kein Inhalt.

Nur Admins: Die SMTP-Konfiguration kann nur von Mandanten-Admins verwaltet werden. Reguläre Benutzer erhalten 403 Forbidden.