{
    "openapi": "3.1.0",
    "info": {
        "title": "Kunden-API MAM-JAHN",
        "version": "1"
    },
    "servers": [
        {
            "url": "https://api-mam-jahn.de/v1"
        }
    ],
    "components": {
        "securitySchemes": {
            "bearer": {
                "type": "http",
                "scheme": "bearer"
            }
        }
    },
    "security": [
        {
            "bearer": []
        }
    ],
    "paths": {
        "/account": {
            "get": {
                "tags": [
                    "Konto und Angebot"
                ],
                "summary": "Konto, Guthaben, Verfügungsrahmen, verfügbarer Betrag, Restlaufzeit in Stunden",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "account:read"
            }
        },
        "/host-lines": {
            "get": {
                "tags": [
                    "Konto und Angebot"
                ],
                "summary": "Hostsysteme mit Grenzen, Preisen (Cent netto je Monat) und Vorlagen; cpu_model nur als öffentliche Bezeichnung (z. B. „AMD EPYC 3rd Gen“), ohne Modellnummer",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "products:read"
            }
        },
        "/os-images": {
            "get": {
                "tags": [
                    "Konto und Angebot"
                ],
                "summary": "Betriebssysteme (slug für Bestellung und Neuinstallation)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "products:read"
            }
        },
        "/ssh-keys": {
            "get": {
                "tags": [
                    "SSH-Schlüssel"
                ],
                "summary": "Alle Schlüssel mit apply_all (gilt für alle Server), last_used_at und target_count (Anzahl Server mit diesem Schlüssel)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "services:read"
            },
            "post": {
                "tags": [
                    "SSH-Schlüssel"
                ],
                "summary": "Schlüssel hinzufügen: name, public_key, optional apply_all",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "name": "laptop",
                                "public_key": "ssh-ed25519 AAAA… du@laptop",
                                "apply_all": true
                            }
                        }
                    }
                }
            }
        },
        "/ssh-keys/{id}": {
            "patch": {
                "tags": [
                    "SSH-Schlüssel"
                ],
                "summary": "Umbenennen und/oder apply_all setzen: gilt für alle Server des Kontos, auch künftige (cloud-init übernimmt neue Schlüssel beim nächsten Start; entfernte bleiben in authorized_keys bis zur Neuinstallation)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "name": "laptop-neu",
                                "apply_all": true
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "SSH-Schlüssel"
                ],
                "summary": "Schlüssel entfernen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/servers": {
            "get": {
                "tags": [
                    "Server"
                ],
                "summary": "Alle Server (Seiten: ?page, ?per_page bis 100)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "services:read"
            },
            "post": {
                "tags": [
                    "Server"
                ],
                "summary": "Server bestellen – Idempotency-Key Pflicht, Antwort 202 mit job und einmaligem root_password",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "orders:create",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "host_line": "de_epyc",
                                "plan_id": 2,
                                "os": "debian-13",
                                "name": "web-01",
                                "ssh_key_ids": [
                                    1
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}": {
            "get": {
                "tags": [
                    "Server"
                ],
                "summary": "Ein Server mit IPs, Stand und laufendem Auftrag",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            },
            "delete": {
                "tags": [
                    "Server"
                ],
                "summary": "Server löschen (Abrechnung endet mit der laufenden Stunde)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:reinstall"
            }
        },
        "/servers/{id}/actions/{action}": {
            "post": {
                "tags": [
                    "Server"
                ],
                "summary": "start, stop (hart), shutdown, reboot, reset (hart, nur laufend) – Antwort 202 mit job; dieselbe Aktion höchstens einmal je Minute und Server",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "action",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "x-scope": "services:power"
            }
        },
        "/servers/{id}/reinstall": {
            "post": {
                "tags": [
                    "Server"
                ],
                "summary": "Neu installieren: os, ssh_key_ids (ohne Angabe: die dem Server zugewiesenen Schlüssel; Schlüssel mit apply_all kommen immer dazu) – löscht alle Daten",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:reinstall",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "os": "debian-13",
                                "ssh_key_ids": [
                                    1
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/media": {
            "get": {
                "tags": [
                    "Server"
                ],
                "summary": "Eingelegtes ISO, Bootreihenfolge, Rettungssystem und alle einlegbaren ISOs",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/iso": {
            "post": {
                "tags": [
                    "Server"
                ],
                "summary": "ISO einlegen: iso (Slug) oder iso_id – Antwort 202 mit job",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "iso": "debian-13-netinst"
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Server"
                ],
                "summary": "ISO auswerfen – Antwort 202 mit job",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/servers/{id}/boot": {
            "post": {
                "tags": [
                    "Server"
                ],
                "summary": "Bootreihenfolge: boot = disk | cdrom (greift beim nächsten Start)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "boot": "cdrom"
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/rescue": {
            "post": {
                "tags": [
                    "Server"
                ],
                "summary": "Rettungssystem starten (Neustart von CD) – Antwort 202 mit job",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            },
            "delete": {
                "tags": [
                    "Server"
                ],
                "summary": "Rettungssystem beenden, vorherigen Stand wiederherstellen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/servers/{id}/hostname": {
            "post": {
                "tags": [
                    "Server"
                ],
                "summary": "Hostname ändern: hostname – DNS (A/AAAA, rDNS) wird nachgezogen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "hostname": "web-01.example.de"
                            }
                        }
                    }
                }
            }
        },
        "/jobs/{id}": {
            "get": {
                "tags": [
                    "Server"
                ],
                "summary": "Stand eines Auftrags: queued, running, done, failed",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/status": {
            "get": {
                "tags": [
                    "Server: Zustand und Verlauf"
                ],
                "summary": "Live-Werte: state, uptime (s), cpu (%), mem/maxmem, netin/netout, diskread/diskwrite (Byte), disk_used/disk_total laut Gast-Agent",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/metrics": {
            "get": {
                "tags": [
                    "Server: Zustand und Verlauf"
                ],
                "summary": "Verlauf ?range=hour|day|week|month|year: Punkte mit cpu (%), mem (Byte), Netz und Platte (Byte/s)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/traffic": {
            "get": {
                "tags": [
                    "Server: Zustand und Verlauf"
                ],
                "summary": "Traffic je Tag ?days=14|30|90: rx, tx, Summen in Byte. status, metrics und traffic auch für Server, die dir mit Recht „monitor“ freigegeben sind",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/jobs": {
            "get": {
                "tags": [
                    "Server: Zustand und Verlauf"
                ],
                "summary": "Aufträge dieses Servers, neueste zuerst (Seiten: ?page, ?per_page bis 100)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/tasks": {
            "get": {
                "tags": [
                    "Server: Zustand und Verlauf"
                ],
                "summary": "Laufende Proxmox-Aufgaben der VM (Backup, Wiederherstellung, Umzug …): type, label, status, started_at",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/password-reset": {
            "post": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "Neues Root-Passwort (Gast-Agent sofort, sonst Cloud-Init beim nächsten Start) – Antwort mit password, nur einmal",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/servers/{id}/ssh-keys": {
            "post": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "SSH-Schlüssel aus dem Konto per Cloud-Init hinterlegen und dem Server zuweisen: ssh_key_ids[] (Schlüssel mit apply_all kommen immer dazu; neue greifen beim nächsten Start, entfernte bleiben in authorized_keys bis zur Neuinstallation)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "ssh_key_ids": [
                                    1,
                                    2
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/network": {
            "get": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "IPv4, IPv6-Netz und rDNS je IP (Name, Standardname, Stand)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/servers/{id}/rdns": {
            "post": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "rDNS setzen: ip, name (leer = Standardname) – der A/AAAA-Eintrag muss vorher auf die IP zeigen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "ip": "192.0.2.5",
                                "name": "mail.example.de"
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/firewall": {
            "get": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "Firewall: enabled, policy_in, policy_out und Regeln in Reihenfolge",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            },
            "put": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "Firewall einstellen: enabled, policy_in, policy_out (ACCEPT | DROP | REJECT)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "enabled": true,
                                "policy_in": "DROP",
                                "policy_out": "ACCEPT"
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/firewall/rules": {
            "post": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "Regel anlegen: direction (in|out), action (ACCEPT|DROP|REJECT), proto, dport, source, comment",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "direction": "in",
                                "action": "ACCEPT",
                                "proto": "tcp",
                                "dport": "22",
                                "source": "203.0.113.0/24"
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/firewall/rules/{rule}": {
            "patch": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "Regel ändern (nur mitgeschickte Felder, auch enabled)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "rule",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "enabled": false
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "Regel löschen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "rule",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/servers/{id}/firewall/rules/{rule}/move": {
            "post": {
                "tags": [
                    "Server: Zugang und Netz"
                ],
                "summary": "Regel verschieben: direction = up | down",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "rule",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "direction": "up"
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/backups": {
            "get": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Backups (neueste zuerst): volid, created_at, size, note, protected; limit und used",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            },
            "post": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Backup anlegen: note (optional) – der Server läuft weiter",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:backups",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "note": "vor Update"
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Backup löschen: volid (im Body oder ?volid=)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:backups",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "volid": "pbs:backup/vm/200/2026-10-25T03:00:00Z"
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/backups/restore": {
            "post": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Backup zurückspielen: volid, confirm=true – überschreibt den aktuellen Stand",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:backups",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "volid": "pbs:backup/vm/200/2026-10-25T03:00:00Z",
                                "confirm": true
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/snapshots": {
            "get": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Snapshots (neueste zuerst): name, description, created_at, vmstate, rollback_possible; limit",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            },
            "post": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Snapshot anlegen: name (2–40, beginnt mit Buchstabe), description, vmstate (mit RAM)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:backups",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "name": "vor-update",
                                "description": "Kernel 6.12"
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/snapshots/{name}/rollback": {
            "post": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Auf Snapshot zurücksetzen: confirm=true – Änderungen seither gehen verloren",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "name",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "x-scope": "services:backups",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "confirm": true
                            }
                        }
                    }
                }
            }
        },
        "/servers/{id}/snapshots/{name}": {
            "delete": {
                "tags": [
                    "Server: Backups und Snapshots"
                ],
                "summary": "Snapshot löschen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "name",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        }
                    }
                ],
                "x-scope": "services:backups"
            }
        },
        "/services": {
            "get": {
                "tags": [
                    "Verträge und Guthaben"
                ],
                "summary": "Alle Verträge mit Produkt, Laufzeit, Stand und Verlängerung (Filter: ?whmcs_id= alte Vertrags-ID, ?server_id=, ?customer_id= Reseller)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "services:read"
            }
        },
        "/services/{id}": {
            "get": {
                "tags": [
                    "Verträge und Guthaben"
                ],
                "summary": "Ein Vertrag mit Optionen und Server",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:read"
            }
        },
        "/services/{id}/credentials": {
            "get": {
                "tags": [
                    "Verträge und Guthaben"
                ],
                "summary": "Zugangsdaten eines neuen Servers – nur einmal und höchstens 24 Stunden nach der Bereitstellung",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:credentials"
            }
        },
        "/credit/topup": {
            "post": {
                "tags": [
                    "Verträge und Guthaben"
                ],
                "summary": "Guthaben aufladen: amount_cents (oder amount in Euro), optional provider – Antwort mit Zahlungslink des Zahlungsanbieters",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "credit:topup",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "amount_cents": 2000,
                                "provider": "paypal"
                            }
                        }
                    }
                }
            }
        },
        "/credit/topup/{id}": {
            "get": {
                "tags": [
                    "Verträge und Guthaben"
                ],
                "summary": "Stand einer Aufladung",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "credit:topup"
            }
        },
        "/credit/auto-topup": {
            "get": {
                "tags": [
                    "Verträge und Guthaben"
                ],
                "summary": "Automatische Aufladung: enabled, threshold_cents, target_cents, monthly_cap_cents (brutto), diesen Monat genutzt, Pause, Standard-Zahlart, letzte Aufladungen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "account:read"
            },
            "put": {
                "tags": [
                    "Verträge und Guthaben"
                ],
                "summary": "Automatische Aufladung einschalten/ändern (enabled=true, Schwelle, Ziel, Monatsgrenze in Cent, consent=true – bestätigt den Einwilligungstext aus consent_text) oder abschalten (enabled=false). Nur Inhaber/Abrechnung, keine Partner-Apps",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "credit:topup",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "enabled": true,
                                "threshold_cents": 1000,
                                "target_cents": 5000,
                                "monthly_cap_cents": 15000,
                                "consent": true
                            }
                        }
                    }
                }
            }
        },
        "/transactions": {
            "get": {
                "tags": [
                    "Abrechnung"
                ],
                "summary": "Buchungen (Aufladungen, Verbrauch je Stunde, Erstattungen)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "account:read"
            }
        },
        "/usage": {
            "get": {
                "tags": [
                    "Abrechnung"
                ],
                "summary": "Verbrauch je Server im Monat (?period=JJJJ-MM)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "account:read"
            }
        },
        "/invoices": {
            "get": {
                "tags": [
                    "Abrechnung"
                ],
                "summary": "Rechnungen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "invoices:read"
            }
        },
        "/invoices/{id}": {
            "get": {
                "tags": [
                    "Abrechnung"
                ],
                "summary": "Eine Rechnung mit Positionen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "invoices:read"
            }
        },
        "/invoices/{id}/xml": {
            "get": {
                "tags": [
                    "Abrechnung"
                ],
                "summary": "E-Rechnung als CII-XML (EN 16931)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "invoices:read"
            }
        },
        "/products": {
            "get": {
                "tags": [
                    "Produkte und Bestellung"
                ],
                "summary": "Für die API freigegebene Produkte mit Laufzeiten, Preisen (Cent netto und brutto für dein Konto), Optionen, Bestand und Vorverkauf",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "products:read"
            }
        },
        "/products/{id}": {
            "get": {
                "tags": [
                    "Produkte und Bestellung"
                ],
                "summary": "Ein Produkt mit Beschreibung, Bestellfeldern (customfields: id, label, type, required, options) und Addons mit Preisen; Konfiguratoren mit Grenzen (min/max) und Preis je Einheit (404, wenn nicht für die API freigegeben)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "products:read"
            }
        },
        "/orders/quote": {
            "post": {
                "tags": [
                    "Produkte und Bestellung"
                ],
                "summary": "Preis berechnen, ohne zu bestellen: product_id, term, options, domain, coupon – Summe, Steuer, Fehlbetrag",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "products:read",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "product_id": 12,
                                "term": 12,
                                "options": {
                                    "7": 31
                                }
                            }
                        }
                    }
                }
            }
        },
        "/orders": {
            "post": {
                "tags": [
                    "Produkte und Bestellung"
                ],
                "summary": "Bestellen aus dem Guthaben – Idempotency-Key Pflicht, accept_terms und accept_withdrawal; Zusatzfelder fields (Feld-ID => Wert, auch customfields) und addons[]; reicht das Guthaben nicht: 402, nichts bestellt",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "orders:create",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "product_id": 12,
                                "term": 12,
                                "options": {
                                    "7": 31
                                },
                                "hostname": "web-01",
                                "fields": {
                                    "4": "Projekt X"
                                },
                                "addons": [
                                    3
                                ],
                                "accept_terms": true,
                                "accept_withdrawal": true
                            }
                        }
                    }
                }
            },
            "get": {
                "tags": [
                    "Produkte und Bestellung"
                ],
                "summary": "Deine Bestellungen (Seiten: ?page, ?per_page bis 100)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "orders:create"
            }
        },
        "/orders/{id}": {
            "get": {
                "tags": [
                    "Produkte und Bestellung"
                ],
                "summary": "Eine Bestellung mit Positionen, Diensten und Rechnung",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "orders:create"
            }
        },
        "/domains/check": {
            "get": {
                "tags": [
                    "Domains"
                ],
                "summary": "Verfügbarkeit und deine Preise (?domain=, Cent brutto, 1 Jahr): register, transfer, renew, restore",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "domains:read"
            }
        },
        "/domains/pricing": {
            "get": {
                "tags": [
                    "Domains"
                ],
                "summary": "Alle Endungen mit deinen Preisen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "domains:read"
            }
        },
        "/domains": {
            "get": {
                "tags": [
                    "Domains"
                ],
                "summary": "Deine Domains mit Stand, Registry-Ablauf, Fälligkeit und Verlängerungspreis",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "domains:read"
            },
            "post": {
                "tags": [
                    "Domains"
                ],
                "summary": "Registrieren bzw. umziehen (type=transfer, auth_code) – Idempotency-Key Pflicht, accept_terms und accept_withdrawal, nur aus dem Guthaben (sonst 402)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "domains:order",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "domain": "mein-projekt.de",
                                "accept_terms": true,
                                "accept_withdrawal": true
                            }
                        }
                    }
                }
            }
        },
        "/domains/{id}": {
            "get": {
                "tags": [
                    "Domains"
                ],
                "summary": "Eine Domain mit Nameservern",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:read"
            }
        },
        "/domains/{id}/nameservers": {
            "post": {
                "tags": [
                    "Domains"
                ],
                "summary": "Nameserver setzen: nameservers[] (2–6) oder ours=true",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "ours": true
                            }
                        }
                    }
                }
            }
        },
        "/domains/{id}/authcode": {
            "post": {
                "tags": [
                    "Domains"
                ],
                "summary": "Auth-Code für den Umzug abrufen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:manage"
            }
        },
        "/domains/{id}/renewal": {
            "post": {
                "tags": [
                    "Domains"
                ],
                "summary": "Verlängerung an/aus: auto_renew=true|false",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:order",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "auto_renew": false
                            }
                        }
                    }
                }
            }
        },
        "/domains/{id}/privacy": {
            "get": {
                "tags": [
                    "Domains"
                ],
                "summary": "Whois-Schutz: Stand",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:read"
            },
            "post": {
                "tags": [
                    "Domains"
                ],
                "summary": "Whois-Schutz an/aus: enabled=true|false",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "enabled": true
                            }
                        }
                    }
                }
            }
        },
        "/domains/{id}/dnssec": {
            "get": {
                "tags": [
                    "Domains"
                ],
                "summary": "DNSSEC: Stand und hinterlegte Schlüssel",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:read"
            },
            "post": {
                "tags": [
                    "Domains"
                ],
                "summary": "DNSSEC-Schlüssel setzen: records[] (keyTag, algorithm, digestType, digest) oder ds als Text",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:manage"
            },
            "delete": {
                "tags": [
                    "Domains"
                ],
                "summary": "DNSSEC ausschalten",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "domains:manage"
            }
        },
        "/domain-profiles": {
            "get": {
                "tags": [
                    "Domains"
                ],
                "summary": "Deine Kontaktprofile für abweichende Inhaber",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "domains:read"
            }
        },
        "/shares": {
            "get": {
                "tags": [
                    "Freigaben"
                ],
                "summary": "Vergebene (outgoing), mit dir geteilte (incoming) und offene Einladungen an dich, dazu die möglichen Rechte",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "services:read"
            },
            "post": {
                "tags": [
                    "Freigaben"
                ],
                "summary": "Dienst freigeben: service_id, email, permissions[] (view ist immer dabei)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "service_id": 877,
                                "email": "kollegin@example.de",
                                "permissions": [
                                    "view",
                                    "start",
                                    "stop"
                                ]
                            }
                        }
                    }
                }
            }
        },
        "/shares/{id}": {
            "patch": {
                "tags": [
                    "Freigaben"
                ],
                "summary": "Rechte einer vergebenen Freigabe ändern: permissions[]",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "permissions": [
                                    "view",
                                    "reboot"
                                ]
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Freigaben"
                ],
                "summary": "Vergebene Freigabe zurückziehen bzw. angenommene Freigabe verlassen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/shares/{id}/accept": {
            "post": {
                "tags": [
                    "Freigaben"
                ],
                "summary": "Einladung annehmen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/shares/{id}/decline": {
            "post": {
                "tags": [
                    "Freigaben"
                ],
                "summary": "Einladung ablehnen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "services:manage"
            }
        },
        "/reseller": {
            "get": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Stufe und Rabatt in %, Warnschwelle, Guthaben, Monatskosten, Zahl der Endkunden",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "reseller:manage"
            }
        },
        "/reseller/report": {
            "get": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Kosten je Endkunde (Cent brutto je Laufzeit und Monat) und nicht zugeordnete Dienste",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "reseller:manage"
            }
        },
        "/reseller/customers": {
            "get": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Deine Endkunden mit zugeordneten Diensten (service_ids)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "reseller:manage"
            },
            "post": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Endkunde anlegen: name, company, ref (deine Nummer), email, note",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "reseller:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "name": "Max Muster",
                                "ref": "K-1042"
                            }
                        }
                    }
                }
            }
        },
        "/reseller/customers/{id}": {
            "get": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Ein Endkunde mit Diensten und Kosten",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "reseller:manage"
            },
            "patch": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Endkunde ändern (nur mitgeschickte Felder)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "reseller:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "note": "zahlt jährlich"
                            }
                        }
                    }
                }
            },
            "delete": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Endkunde löschen (Zuordnungen fallen weg, Dienste bleiben)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "reseller:manage"
            }
        },
        "/reseller/assignments": {
            "post": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Dienst zuordnen: service_id, customer_id (0 oder leer = Zuordnung lösen)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "x-scope": "reseller:manage",
                "requestBody": {
                    "content": {
                        "application/json": {
                            "example": {
                                "service_id": 877,
                                "customer_id": 3
                            }
                        }
                    }
                }
            }
        },
        "/reseller/customers/{id}/domains": {
            "get": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Domains eines Endkunden",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "reseller:manage"
            }
        },
        "/reseller/customers/{id}/domains/{domain}": {
            "post": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Domain einem Endkunden zuordnen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "domain",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "reseller:manage"
            },
            "delete": {
                "tags": [
                    "Reseller"
                ],
                "summary": "Domain-Zuordnung lösen",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "parameters": [
                    {
                        "name": "id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    },
                    {
                        "name": "domain",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "integer"
                        }
                    }
                ],
                "x-scope": "reseller:manage"
            }
        },
        "/oauth/token": {
            "post": {
                "tags": [
                    "Partner-Apps (OAuth)"
                ],
                "summary": "Code gegen App-Schlüssel tauschen: grant_type=authorization_code, code, client_id, client_secret, redirect_uri (ohne Bearer-Schlüssel)",
                "responses": {
                    "default": {
                        "description": "Antwort als JSON, Fehler als application/problem+json"
                    }
                },
                "security": []
            }
        }
    }
}