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/v1Authentifizierung
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:
{
"message": "Human-readable error description",
"errors": {
"field_name": ["Validation error message"]
}
}| Status | Bedeutung |
|---|---|
| 401 | Fehlender oder ungültiger Authentifizierungs-Token |
| 403 | Unzureichende Berechtigungen (kein Reseller, oder das Team gehört nicht zu dir) |
| 404 | Ressource nicht gefunden |
| 422 | Validierung fehlgeschlagen |
| 429 | Rate-Limit überschritten |
Authentifizierungs-Endpoints
Token erstellen
API-Token durch Eintausch deiner Zugangsdaten erhalten.
POST /auth/tokenRate-Limit: throttle:auth (strenger als das Standard-API-Limit)
Request Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
email | string | ja | E-Mail-Adresse deines Kontos |
password | string | ja | Passwort deines Kontos |
device_name | string | ja | Bezeichner für den Token (z. B. "CI Server") |
Beispiel:
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):
{
"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 mitrk-, Impersonation-Tokens mitik-und Service-API-Keys verwalteter Teams mitsvc-. 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 /userBeispiel:
curl https://app.hoppla.dev/api/v1/user \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"id": "9a1b2c3d-e5f6-...",
"name": "Reseller Account",
"email": "[email protected]",
"tenant_id": "tenant-uuid-...",
"role": "admin",
"language": "en"
}Token widerrufen
DELETE /auth/tokenBeispiel:
curl -X DELETE https://app.hoppla.dev/api/v1/auth/token \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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-teamsQuery-Parameter:
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
page | integer | 1 | Seitennummer |
per_page | integer | 15 | Einträge pro Seite |
Beispiel:
curl "https://app.hoppla.dev/api/v1/reseller/managed-teams?page=1" \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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-teamsRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ja | Anzeigename des Teams (max. 255 Zeichen) |
slug | string | ja | URL-sicherer Bezeichner (Kleinbuchstaben, nur Bindestriche, max. 100 Zeichen, eindeutig) |
plan | string | nein | Tarifmodell: free, hobby, starter oder pro (Standard: free) |
label | string | nein | Internes Label für deine Referenz (max. 255 Zeichen) |
admin_email | string | nein | E-Mail-Adresse für den Admin-Benutzer des Teams |
admin_name | string | nein | Name des Admin-Benutzers des Teams |
admin_password | string | bedingt | Pflicht, wenn admin_email angegeben wird (min. 12 Zeichen, wird gegen Datenleck-Datenbanken geprüft) |
trial_days | integer | nein | Das 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:
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):
{
"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.provisionedWebhook-Event ausgelöst.
Verwaltetes Team abrufen
GET /reseller/managed-teams/{id}Beispiel:
curl https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-... \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | nein | Anzeigename des Teams |
label | string | nein | Internes Label |
plan | string | nein | Tarifmodell: free, hobby, starter oder pro |
trial_days | integer | nein | Eine Testphase setzen (1–365 Tage ab jetzt). Nutze 0, um eine aktive Testphase zu beenden. |
Beispiel:
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):
{
"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:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
confirm_name | string | ja | Muss exakt dem Team-Namen entsprechen, um die Löschung zu bestätigen |
Beispiel:
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.deletedWebhook-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}/pauseRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
reason | string | nein | Grund für das Pausieren (max. 50 Zeichen) |
Beispiel:
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):
{
"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}/unpauseBeispiel:
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../unpause \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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/trashedQuery-Parameter:
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
page | integer | 1 | Seitennummer |
per_page | integer | 15 | Einträge pro Seite |
Beispiel:
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.
{
"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}/restoreBeispiel:
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.
{
"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}/summaryBeispiel:
curl https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../summary \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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}/usageQuery-Parameter:
| Parameter | Typ | Standard | Beschreibung |
|---|---|---|---|
period | string | aktueller Monat | Monat im Format YYYY-MM (z. B. 2026-03) |
Beispiel:
curl "https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../usage?period=2026-03" \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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.
| Scope | Beschreibung |
|---|---|
teams:read | Verwaltete Teams, Zusammenfassungen, Nutzung, Feature-Overrides, Templates, Provisionierungsprofile sowie mandantenübergreifende Übersicht/Berichte auflisten und anzeigen |
teams:write | Verwaltete Teams erstellen, aktualisieren, löschen, pausieren, fortsetzen, wiederherstellen; Templates, Provisionierungsprofile, Batch-Operationen und Impersonation-Tokens verwalten |
members:read | Mitglieder und Einladungen verwalteter Teams auflisten |
members:write | Team-Mitglieder erstellen, aktualisieren, löschen; Einladungen verwalten; MFA zurücksetzen |
members:manage | Vollständige Mitgliederverwaltung (gewährt sowohl members:read als auch members:write) |
branding:read | Branding-Konfiguration verwalteter Teams anzeigen |
branding:write | Branding-Konfiguration verwalteter Teams aktualisieren |
branding:manage | Vollständige Branding-Verwaltung (gewährt sowohl branding:read als auch branding:write) |
sso:read | Partner-SSO-Konfiguration anzeigen |
sso:write | Partner-SSO-Konfiguration aktualisieren, Secrets rotieren, SSO-Links erzeugen |
sso:manage | Vollständige SSO-Verwaltung (gewährt sowohl sso:read als auch sso:write) |
portal:read | Portal-Einstellungen, Custom Domains und E-Mail-Unterdrückung anzeigen |
portal:write | Portal-Einstellungen aktualisieren, Custom Domains verwalten, E-Mail-Unterdrückung aktualisieren |
portal:manage | Vollständige Portal-Verwaltung (gewährt sowohl portal:read als auch portal:write) |
api-keys:read | API-Keys verwalteter Teams auflisten |
api-keys:write | API-Keys verwalteter Teams erstellen und widerrufen |
api-keys:manage | Vollständige API-Key-Verwaltung (gewährt sowohl api-keys:read als auch api-keys:write) |
webhooks:read | Reseller-Webhooks auflisten und Zustellungsprotokolle anzeigen |
webhooks:write | Reseller-Webhooks erstellen, aktualisieren und löschen |
webhooks:manage | Vollständige Webhook-Verwaltung (gewährt sowohl webhooks:read als auch webhooks:write) |
notifications:read | Benachrichtigungskanäle und -regeln eines verwalteten Teams anzeigen |
notifications:write | Benachrichtigungskanäle und -regeln eines verwalteten Teams erstellen, aktualisieren und löschen |
notifications:manage | Vollständige Benachrichtigungs-Verwaltung (gewährt sowohl notifications:read als auch notifications:write) |
maintenance:read | Wartungsfenster eines verwalteten Teams anzeigen |
maintenance:write | Wartungsfenster eines verwalteten Teams erstellen, aktualisieren und löschen |
maintenance:manage | Vollständige Wartungs-Verwaltung (gewährt sowohl maintenance:read als auch maintenance:write) |
status-pages:read | Statusseiten eines verwalteten Teams anzeigen |
status-pages:write | Statusseiten eines verwalteten Teams erstellen, aktualisieren und löschen |
status-pages:manage | Vollständige Statusseiten-Verwaltung (gewährt sowohl status-pages:read als auch status-pages:write) |
monitors:read | Monitore, Checks und Zeitreihen-Daten eines verwalteten Teams anzeigen |
monitors:write | Monitore und Checks eines verwalteten Teams erstellen, aktualisieren, löschen, aktivieren/deaktivieren, Läufe anfordern und stummschalten |
monitors:manage | Vollständige Monitor-Verwaltung (gewährt sowohl monitors:read als auch monitors:write) |
incidents:read | Vorfälle eines verwalteten Teams anzeigen |
incidents:write | Vorfälle eines verwalteten Teams aktualisieren und schließen |
incidents:manage | Vollstä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/scopesAntwort (200):
{
"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/tokensAntwort (200):
{
"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:
curl https://app.hoppla.dev/api/v1/reseller/tokens/token-uuid-... \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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/tokensRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ja | Token-Name (max. 255 Zeichen) |
scopes | string[] | ja | Array von Scope-Werten (min. 1) |
expires_at | datetime | nein | Ablaufdatum (ISO 8601). Weglassen für keinen Ablauf |
Beispiel:
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):
{
"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_tokenwird nur einmal zurückgegeben. Bewahre es sicher auf. Reseller-Verwaltungstokens beginnen mitrk-; 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}/rotateRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
grace_period_hours | integer | nein | Wie lange der alte Token gültig bleibt (1–168 h, Standard: 24) |
Beispiel:
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):
{
"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_tokenin 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}/toggleAntwort (200):
{
"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:
- Dein Mandant muss ein Reseller-Konto sein.
- 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-Typ | Zugriff auf Reseller-Verwaltungs-Endpoints |
|---|---|
| Allgemeiner Token (beliebiger Scope) | Kein Zugriff auf Reseller-Verwaltungs-Endpoints |
Reseller-Token mit teams:read | Verwaltete Teams auflisten/anzeigen |
Reseller-Token mit teams:write | Verwaltete Teams erstellen/aktualisieren/löschen |
Reseller-Token mit monitors:read | Monitore und Checks eines verwalteten Teams anzeigen |
Reseller-Token mit monitors:write | Monitore 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-tokensLiefert nur nicht abgelaufene Tokens.
Antwort (200):
{
"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-tokensRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
ttl_minutes | integer | nein | Lebensdauer des Tokens in Minuten (1–15, Standard: 15) |
scopes | string[] | nein | Array aus "read" und/oder "write" (Standard: beide) |
label | string | nein | Beschreibendes Label für Audit-Zwecke (max. 255 Zeichen) |
Beispiel:
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):
{
"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-IdHeader erforderlich. Impersonation-Tokens beginnen mitik-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:
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-ssoAntwort (200):
{
"data": {
"enabled": true,
"has_shared_secret": true,
"hide_password_login": false,
"auto_register": true
}
}Partner-SSO-Konfiguration aktualisieren
PATCH /reseller/managed-teams/{id}/partner-ssoRequest Body: Alle Felder sind optional.
| Feld | Typ | Beschreibung |
|---|---|---|
enabled | boolean | Partner-SSO-Authentifizierung aktivieren/deaktivieren |
hide_password_login | boolean | Das 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_register | boolean | Automatisch Konten für neue Benutzer anlegen, die sich per SSO anmelden |
auto_link_existing_users | boolean | Wer 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_loginautomatisch auffalsezurück. Dies ist eine Sicherheitsmaßnahme, um Aussperrungen zu verhindern, falls das neue Secret noch nicht ausgerollt wurde. Aktivierehide_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-secretAntwort (200):
{
"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.
SSO-Login-Link erzeugen
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-linkRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
user_email | ja | E-Mail des anzumeldenden Benutzers | |
user_name | string | nein | Name für die automatische Registrierung (falls der Benutzer noch nicht existiert) |
redirect_to | string | nein | Pfad, zu dem nach dem Login weitergeleitet wird (z. B. /dashboard/monitors) |
Beispiel:
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):
{
"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:
- Wenn das verwaltete Team eine verifizierte eigene Portal-Domain hat, wird diese verwendet (z. B.
https://monitoring.acme.com/sso/partner?token=...) - Andernfalls wird, falls der Reseller eine verifizierte Portal-Domain hat, diese verwendet (z. B.
https://portal.reseller.com/sso/partner?token=...) - Als Fallback wird
https://app.hoppla.devverwendet
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-overridesAntwort (200):
{
"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-overridesRequest Body:
{
"overrides": {
"monitors": 100,
"lighthouse_audits": true,
"status_pages": "__remove__"
}
}Override-Werte nach Feature-Typ:
| Feature | Typ | Werte |
|---|---|---|
monitors | number oder null | Anzahl-Limit oder null für unbegrenzt |
status_pages | number oder null | Anzahl-Limit oder null für unbegrenzt |
team_members | number oder null | Anzahl-Limit oder null für unbegrenzt |
agent_limit | number | Anzahl der Server-Agents |
min_check_interval | number | Mindestintervall in Sekunden |
data_retention_days | number | Tage der Datenaufbewahrung |
cron_heartbeats | boolean | Aktivieren/Deaktivieren |
server_monitoring | boolean | Aktivieren/Deaktivieren |
lighthouse_audits | boolean | Aktivieren/Deaktivieren |
geo_audits | boolean | Aktivieren/Deaktivieren |
site_crawls | boolean | Aktivieren/Deaktivieren |
web_vitals | boolean | Aktivieren/Deaktivieren |
custom_domains | boolean | Aktivieren/Deaktivieren |
on_call_schedules | boolean | Aktivieren/Deaktivieren |
api_access | string | "read" oder "full" |
notification_channels | array | Erlaubte Kanaltypen, z. B. ["email", "slack", "webhook"] |
ai_incident_analysis | boolean | KI-Vorfallanalyse aktivieren/deaktivieren |
ai_analysis_monthly_limit | number oder null | KI-Analysen pro Monat (0–10.000) oder null für unbegrenzt |
ai_report_monthly_limit | number | KI-Zusammenfassungen des monatlichen PDF-Berichts pro Monat (0–100) |
mobile_push_notifications | boolean | Mobile Push aktivieren/deaktivieren (nur wenn dein Konto dafür lizenziert ist) |
white_label_branding | boolean | Die Admins des Teams dürfen sein Branding selbst setzen. Du kannst deine verwalteten Teams auch ohne das branden |
Spezialwerte:
| Wert | Bedeutung |
|---|---|
null | Unbegrenzt (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
422abgelehnt; 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}/membersAntwort (200):
{
"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}/membersRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
email | ja | E-Mail-Adresse des Benutzers | |
name | string | nein | Anzeigename des Benutzers (Standard: E-Mail, wenn weggelassen) |
password | string | ja | Initiales Passwort (min. 12 Zeichen, wird gegen Datenleck-Datenbanken geprüft) |
role | string | nein | member (Standard) oder admin |
language | string | nein | en (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:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | nein | Anzeigename des Benutzers (max. 255 Zeichen) |
language | string | nein | en oder de |
Beispiel:
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):
{
"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}/eraseEntfernen 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-mfaBeispiel:
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):
{
"message": "MFA has been reset for this user."
}Team-Einladungen auflisten
GET /reseller/managed-teams/{id}/invitationsAntwort (200):
{
"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}/invitationsRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
email | ja | Einzuladende E-Mail-Adresse | |
role | string | nein | member (Standard) oder admin |
Antwort (201):
{
"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}/resendBeispiel:
curl -X POST https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../invitations/invitation-uuid-.../resend \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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-reportAntwort (200):
{
"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-reportRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
enabled | boolean | ja | Monatliche Berichte aktivieren oder deaktivieren |
recipients | array | ja | E-Mail-Adressen, die den Bericht erhalten (max. 10). Leeres Array = an den Team-Admin gesendet. |
ai_summary | boolean | nein | Die 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:
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-MMErfordert 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-keysAntwort (200):
{
"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-keysRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ja | Key-Name |
scopes | array | nein | Die 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_at | datetime | nein | Ablaufdatum (ISO 8601, muss in der Zukunft liegen). Weglassen für keinen Ablauf |
Beispiel:
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):
{
"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_tokenwird nur einmal zurückgegeben. Bewahre es sicher auf. Service-API-Keys verwalteter Teams beginnen mitsvc-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}/brandingBeispiel:
curl https://app.hoppla.dev/api/v1/reseller/managed-teams/mt-uuid-.../branding \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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}/brandingRequest 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-domainAntwort (200):
{
"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-domainRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
domain | string | ja | Custom 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/verifyPrüft, ob der CNAME-Eintrag korrekt konfiguriert ist.
Portal-Domain entfernen
DELETE /reseller/managed-teams/{id}/portal-domainPortal-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-domainBeispiel:
curl https://app.hoppla.dev/api/v1/reseller/portal-domain \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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-domainRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
domain | string | ja | Custom 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/verifyPrüft, ob der CNAME-Eintrag korrekt konfiguriert ist.
Reseller-Portal-Domain entfernen
DELETE /reseller/portal-domainAntwort (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-settingsAntwort (200):
{
"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-settingsRequest Body: Alle Felder sind optional.
| Feld | Typ | Beschreibung |
|---|---|---|
portal_allow_registration | boolean | Self-Service-Registrierung aktivieren/deaktivieren |
portal_registration_defaults.plan | string | Standard-Tarif für Neuregistrierungen: free, hobby, starter oder pro |
portal_registration_defaults.trial_days | integer|null | Testphase (1–365 Tage). null zum Deaktivieren der Testphase |
portal_registration_defaults.trial_plan | string|null | Tarif während der Testphase. null, um den Standard-Tarif zu verwenden |
portal_registration_defaults.feature_overrides | object|null | Standard-Feature-Overrides (gleiche Felder wie unter Feature-Overrides) |
Beispiel:
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-suppressionAntwort (200):
{
"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-suppressionRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
suppressed_types | string[] | ja | Array der zu unterdrückenden E-Mail-Typ-Schlüssel (siehe verfügbare Typen oben) |
Beispiel:
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/overviewScope: teams:read
Antwort (200):
{
"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/monitorsScope: teams:read
| Parameter | Typ | Beschreibung |
|---|---|---|
tenant_id | uuid | Auf ein verwaltetes Team filtern |
status | string | up, down, warning, paused |
is_enabled | bool | Nach aktiviertem Zustand filtern |
search | string | Nach Name oder URL suchen |
tag | string | Nach Tag filtern |
type | string | Monitor-Typ (http, ping, tcp) |
sort | string | name, status, created_at, url |
sort_dir | string | asc, desc |
per_page | int | Max. 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/incidentsScope: teams:read
| Parameter | Typ | Beschreibung |
|---|---|---|
tenant_id | uuid | Auf ein verwaltetes Team filtern |
status | string | investigating, identified, monitoring, resolved |
severity | string | Kommagetrennt: critical,major |
acknowledged | bool | Nach Bestätigung filtern |
since | datetime | Nur Vorfälle nach diesem Zeitpunkt |
sort | string | started_at, severity, updated_at |
per_page | int | Max. 250 |
Mandantenübergreifender Bericht
Monatliche Zusammenfassung pro Mandant über Monitore, Uptime und Vorfälle.
GET /reseller/reportScope: teams:read
| Parameter | Typ | Beschreibung |
|---|---|---|
period | string | YYYY-MM (Standard: aktueller Monat) |
tenant_ids | string | Kommagetrennte 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-historyScope: teams:read
Antwort (200):
{
"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-typesScope: webhooks:read
Liefert alle abonnierbaren Event-Typen, nach Kategorie gruppiert.
Webhook erstellen
POST /reseller/webhooksScope: webhooks:write
Request:
{
"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:writeZustellungsprotokolle
GET /reseller/webhooks/{id}/deliveriesScope: 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/batchScope: teams:write
Request:
{
"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{
"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{ "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{
"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{ "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{ "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:
{
"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{
"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:
{
"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-01Liefert 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)
| Parameter | Typ | Beschreibung |
|---|---|---|
is_enabled | bool | Nach aktiviertem Zustand filtern |
status | string | up, down, warning, paused, maintenance |
check_type | string | Nur Monitore mit diesem Check-Typ |
sort | string | name, created_at, url, check_interval |
sort_dir | string | asc, desc |
created_after | date | Erstellt nach diesem Datum |
created_before | date | Erstellt vor diesem Datum |
Vorfälle (GET /incidents)
| Parameter | Typ | Beschreibung |
|---|---|---|
severity | string | Kommagetrennt: critical,major,minor |
check_type | string | Nach ursprünglichem Check-Typ filtern |
acknowledged | bool | Nach Bestätigungsstatus filtern |
snoozed | bool | Nach Snooze-Status filtern |
since | datetime | Nur Vorfälle nach diesem Zeitpunkt |
sort | string | started_at, severity, updated_at, resolved_at |
Verwaltete Teams (GET /reseller/managed-teams)
| Parameter | Typ | Beschreibung |
|---|---|---|
search | string | Nach Team-Name oder Label suchen |
plan | string | Kommagetrennter Tarif-Filter |
status | string | active, paused, trial |
has_incidents | bool | Nur Teams mit aktiven Vorfällen |
trial_expires_before | date | Nach Ende der Testphase filtern |
sort | string | name, created_at, monitors_count |
per_page | int | Max. 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:
| Ressource | Endpoints | Scope-Domäne |
|---|---|---|
| Benachrichtigungskanäle | GET/POST .../notification-channels, GET/PATCH/DELETE .../notification-channels/{cid} | notifications |
| Benachrichtigungsregeln | GET/POST .../notification-rules, GET/PATCH/DELETE .../notification-rules/{rid} | notifications |
| Eskalationsrichtlinien | GET/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 |
| Wartungsfenster | GET/POST .../maintenance-windows, GET/PATCH/DELETE .../maintenance-windows/{mid} | maintenance |
| Statusseiten | GET/POST .../status-pages, GET/PATCH/DELETE .../status-pages/{spid} | status-pages |
| Monitore | GET/POST .../monitors, GET/PATCH/DELETE .../monitors/{mid} | monitors |
| Monitor-Checks | .../monitors/{mid}/checks sowie die Aktionen enable, disable, request-run, snooze und timeseries | monitors |
| Vorfälle | GET .../incidents, Aktualisieren/Schließen | incidents |
| Bericht (PDF) | GET .../report.pdf | teams / 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:
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:
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-Idgesetzt ist, beziehen sich alle API-Antworten auf den Ziel-Mandanten. Datenisolierung wird auf Infrastrukturebene erzwungen.
Beispiel: Einen Check in einem verwalteten Team pausieren (snooze):
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:
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:
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:
# 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
| Typ | Konfigurationsfelder |
|---|---|
webhook | url (Pflicht), secret (optional, für HMAC-Signierung) |
email | recipients (Array von E-Mail-Adressen) |
slack | webhook_url |
discord | webhook_url |
microsoft_teams | webhook_url |
pagerduty | routing_key |
telegram | bot_token, chat_id |
Webhook-Kanal erstellen
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:
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 /brandingBeispiel:
curl https://app.hoppla.dev/api/v1/branding \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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 /brandingRequest Body: Alle Felder sind optional. Nur die mitgeschickten Felder werden aktualisiert.
| Feld | Typ | Beschreibung |
|---|---|---|
brand_name | string | Markenname, der in Benachrichtigungen und E-Mails angezeigt wird (max. 100) |
alert_prefix | string | Benachrichtigungs-Präfix, z. B. "Acme Alert!" (max. 50) |
logo_url | url | Logo für helle Hintergründe (max. 500, SSRF-validiert) |
logo_url_dark | url | Logo für dunkle Hintergründe / E-Mail-Header (max. 500, SSRF-validiert) |
symbol_url | url | Quadratisches 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_color | string | Hex-Farbcode, z. B. #6366F1 |
secondary_color | string | Hex-Farbcode für sekundäre Elemente |
favicon_url | url | Favicon-URL (max. 500, SSRF-validiert) |
footer_text | string | E-Mail-Footer-Text (max. 200) |
footer_url | url | E-Mail-Footer-Link-URL (max. 500, SSRF-validiert) |
privacy_url | url | Datenschutz-Link im E-Mail-Footer (max. 500, SSRF-validiert) |
imprint_url | url | Impressum-/Rechtliches-Link im E-Mail-Footer (max. 500, SSRF-validiert) |
upgrade_url | url | Upgrade-/Upsell-Link-URL (max. 500, SSRF-validiert) |
support_url | url | Support-Seiten-Link-URL (max. 500, SSRF-validiert) |
hide_powered_by | boolean | "Powered by Hoppla"-Hinweis entfernen (erfordert das Tarif-Feature white_label_branding) |
notification_from_name | string | Eigener "From"-Name für Benachrichtigungs-E-Mails (max. 100) |
Beispiel:
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_byerfordert das Tarif-Featurewhite_label_branding. Es ohne dieses Feature auftruezu setzen, liefert403 Forbidden.
Verwaltete Teams: Nutze
GET/PATCH /reseller/managed-teams/{id}/branding, um das Branding eines bestimmten verwalteten Teams zu verwalten (erfordert den Scopebranding: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-configBeispiel:
curl https://app.hoppla.dev/api/v1/smtp-config \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"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-configRequest Body:
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
host | string | ja | SMTP-Server-Hostname |
port | integer | ja | Port: 25, 465, 587 oder 2525 |
encryption | string | ja | tls oder ssl |
username | string | nein | SMTP-Benutzername |
password | string | nein | SMTP-Passwort (******** senden, um das bestehende zu behalten) |
from_address | nein | Absender-E-Mail-Adresse | |
from_name | string | nein | Anzeigename des Absenders |
Beispiel:
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/testAuf 5 Anfragen pro Minute begrenzt.
Beispiel:
curl -X POST https://app.hoppla.dev/api/v1/smtp-config/test \
-H "Authorization: Bearer $TOKEN"Antwort (200):
{
"success": true
}SMTP-Konfiguration entfernen
DELETE /smtp-configEntfernt die Custom-SMTP-Konfiguration. E-Mails werden über den Plattform-Standard versendet.
Beispiel:
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.