Manage Portal API — MSP Self-Service Portal
Das Manage-Portal ermöglicht Kunden des MSP-Services die Verwaltung ihrer Server-Instanz: Server-Steuerung, Domain-Konfiguration und Rechnungseinsicht. Nur auf der Master-Installation verfügbar.
Inhalt
1. Authentifizierung
Die Manage-API nutzt einen Bearer Session-Token, der beim Login zurückgegeben wird:
Authorization: Bearer <session_token>
| Eigenschaft | Wert |
|---|---|
| Basis-URL | /api/manage |
| Verfügbarkeit | Nur auf der Master-Installation |
| Session-Dauer | Konfigurierbar (Standard: 24h) |
Suspendierte Instanzen können nur auf /auth/* und /status zugreifen. Alle anderen Endpunkte geben 403 zurück.
2. Auth-Endpunkte
POST /auth/login
Anmeldung mit E-Mail und Passwort. Rate-Limit: 5 Versuche/5 Min.
{
"email": "admin@firma.de",
"password": "geheim"
}
Antwort (200)
{
"token": "session-uuid",
"expires_at": "2026-03-04T10:00:00+00:00",
"instance": {
"id": 1, "name": "acme", "company_name": "Acme Corp",
"status": "online", "status_label": "Online",
"pricing_tier": "standard", "pricing_tier_label": "Standard",
"portal_url": "https://acme.portal.myit.center",
"meshcentral_url": "https://acme.remote.myit.center"
}
}
POST /auth/forgot-password
Passwort-Reset anfordern. Rate-Limit: 3/15 Min. Gleiche Antwort unabhängig von der Existenz des Kontos.
POST /auth/reset-password
Passwort zurücksetzen. Felder: email, token, password, password_confirmation (min. 8 Zeichen).
Weitere Auth-Endpunkte (Session erforderlich)
POST /auth/logout— Session beendenGET /auth/me— Instanz-Informationen abrufenPUT /auth/password— Passwort ändern (current_password+password+password_confirmation)
3. Status & Aktivitätslog
GET /status
Umfassende Statusübersicht der Instanz.
{
"instance": { "id": 1, "name": "acme", "company_name": "Acme Corp", "status": "online" },
"server": {
"status": "online", "health_status": "healthy",
"ipv4": "1.2.3.4", "server_type": "cx22", "datacenter": "nbg1"
},
"billing": {
"status": "active", "pricing_tier": "standard", "monthly_price": "49,00 €",
"trial_ends_at": null, "paid_until": "2026-04-01"
},
"domains": {
"portal_domain": "acme.portal.myit.center",
"custom_portal_domain": "portal.acme.de",
"portal_url": "https://portal.acme.de"
},
"version": { "app_version": "1.2.3", "portal_version": "1.0.0" },
"limits": { "max_customers": 50, "max_devices": 500 }
}
GET /activity-log
Aktivitätslog der Instanz. Query: per_page (Standard 20).
{
"logs": [
{ "id": 1, "action": "manage.login", "description": "Login über Manage-Portal", "level": "info", "created_at": "..." }
],
"meta": { "current_page": 1, "last_page": 3, "total": 45 }
}
4. Server-Steuerung
Rate-Limit: 3 Aktionen pro Minute pro Instanz.
| Methode | Endpunkt | Beschreibung |
|---|---|---|
| POST | /server/reboot | Server neustarten |
| POST | /server/power-off | Server herunterfahren |
| POST | /server/power-on | Server einschalten |
| POST | /server/refresh-status | Server-Status aktualisieren (Hetzner API) |
Antwort (200)
{ "message": "Server Neustart wurde ausgelöst", "action": "reboot" }
Fehler
| Code | Beschreibung |
|---|---|
| 422 | Kein Hetzner-Server zugeordnet |
| 429 | Rate-Limit überschritten |
| 500 | Server-Aktion fehlgeschlagen |
5. Domain-Verwaltung
| Methode | Endpunkt | Beschreibung |
|---|---|---|
| GET | /domains | Aktuelle Domain-Konfiguration + CNAME-Ziel |
| PUT | /domains/custom-portal | Custom Portal-Domain setzen |
| PUT | /domains/custom-meshcentral | Custom MeshCentral-Domain setzen |
| DELETE | /domains/custom-portal | Custom Portal-Domain entfernen |
| DELETE | /domains/custom-meshcentral | Custom MeshCentral-Domain entfernen |
| POST | /domains/check-cname | CNAME-Record prüfen |
Domain setzen — Beispiel
PUT /api/manage/domains/custom-portal
{ "domain": "portal.meinefirma.de" }
Antwort (200)
{
"message": "Domain gespeichert und auf Server angewendet",
"applied": true,
"domain": "portal.meinefirma.de"
}
Voraussetzung: Vor dem Setzen einer Custom-Domain muss ein CNAME-Record auf die Server-IP zeigen. Prüfen Sie dies mit /domains/check-cname.
6. Rechnungen
| Methode | Endpunkt | Beschreibung |
|---|---|---|
| GET | /invoices | Liste + Statistiken (Filter: status, search, per_page) |
| GET | /invoices/{'{id}'} | Detail mit Positionen, Zahlungen, Steuer-Aufschlüsselung |
| GET | /invoices/{'{id}'}/pdf | PDF-Download |
Rechnungsliste — Antwort (200)
{
"invoices": [
{
"id": 1, "invoice_number": "RE-2026-0001",
"title": "Monatliche Lizenz", "status": "sent",
"total_gross": 49.00, "remaining_amount": 49.00,
"invoice_date": "2026-03-01", "due_date": "2026-03-15"
}
],
"stats": { "open_count": 1, "paid_count": 5, "overdue_count": 0, "open_amount": 49.00 },
"meta": { "current_page": 1, "last_page": 1, "total": 6 }
}