{"openapi":"3.1.0","info":{"title":"mam-jahn.de API","version":"1.0","description":"Kunden-API von mam-jahn.de. Schlüssel im Kundenbereich unter „API-Schlüssel“. Test ohne Wirkung mit Header X-MJ-Sandbox: 1. Rechte: account:read, invoices:read, products:read, services:read."},"servers":[{"url":"https://mam-jahn.de/mjapi.php/v1","description":"Live (mit X-MJ-Sandbox: 1 als Sandbox)"}],"tags":[{"name":"Allgemein","description":"Schlüssel prüfen und die maschinenlesbare Beschreibung."},{"name":"Öffentlich (Website)","description":"Katalog, Preise, Steuersätze, Status und Rechtstexte für Websites – ohne Schlüssel, nur öffentliche Daten."},{"name":"Konto","description":"Konto, Guthaben, Rechnungen und deine API-Aufrufe."},{"name":"Bestellen","description":"Produkte mit Preisen und Bestellen mit Guthaben."},{"name":"Verträge","description":"Alle Verträge und die Zugangsdaten neuer Server."},{"name":"Server","description":"Status, Power, Neuinstallation, Hostname, SSH-Key, Passwort."},{"name":"Messwerte","description":"Auslastung, Verlauf, Traffic und Aufgaben."},{"name":"Backups & Snapshots","description":"Sichern, wiederherstellen, löschen."},{"name":"Netzwerk","description":"IPs, rDNS, ISO-Laufwerk und Firewall."},{"name":"Domains","description":"Verfügbarkeit, Preise, registrieren und umziehen mit Guthaben, Nameserver, Authcode, Sperre."},{"name":"Reseller","description":"Endkunden unter deinem Konto (White-Label), Zuordnung, Abrechnung je Endkunde."}],"paths":{"/ping":{"get":{"operationId":"ping","summary":"Schlüssel prüfen","description":"Antwortet mit Kunden-ID und den Rechten des Schlüssels – ideal für einen ersten Test.","tags":["Allgemein"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true,"client_id":42,"scopes":["account:read","services:read"],"sandbox":false,"time":"2026-10-19T12:00:00+02:00"}}}},"401":{"description":"Schlüssel fehlt, ist falsch oder widerrufen","content":{"application/json":{"example":{"error":{"code":"unauthorized","message":"Schlüssel fehlt, ist falsch oder widerrufen"}}}}},"403":{"description":"kein aktiver Vertrag","content":{"application/json":{"example":{"error":{"code":"account_product","message":"kein aktiver Vertrag"}}}}}}}},"/openapi.json":{"get":{"operationId":"openapi","summary":"OpenAPI-Beschreibung","description":"Alle Endpunkte als OpenAPI 3.1 – für Postman, Insomnia, Swagger UI oder Client-Generatoren. Ohne Schlüssel abrufbar.","tags":["Allgemein"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"openapi":"3.1.0","info":{"title":"mam-jahn.de API","version":"1.0"},"paths":{"…":[]}}}}}},"security":[]}},"/oauth/token":{"post":{"operationId":"token","summary":"Partner-App: Code gegen Schlüssel","description":"Nur für Partner-Apps: Nach „Mit mam-jahn verbinden“ kommt der Kunde mit ?code=… zurück. Diesen Code (10 Minuten, einmal) tauscht der Server der App gegen einen Schlüssel nur für diesen Kunden.","tags":["Allgemein"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"grant_type":{"type":"string","description":"immer authorization_code","example":"authorization_code"},"code":{"type":"string","description":"Code aus dem Rücksprung","example":"Rk2…"},"client_id":{"type":"string","description":"Client-ID der App","example":"mja_1a2b3c4d5e6f"},"client_secret":{"type":"string","description":"Client-Secret der App","example":"mjs_…"},"redirect_uri":{"type":"string","description":"dieselbe Rücksprung-Adresse wie beim Verbinden","example":"https://app.example.de/connect/callback"}},"required":["grant_type","code","client_id","client_secret","redirect_uri"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"access_token":"mjk_77be2210_…","token_type":"Bearer","scope":"account:read orders:create services:read services:credentials","client_id":42}}}},"401":{"description":"Client-ID oder Secret falsch","content":{"application/json":{"example":{"error":{"code":"invalid_client","message":"Client-ID oder Secret falsch"}}}}},"400":{"description":"Code ungültig, abgelaufen oder benutzt","content":{"application/json":{"example":{"error":{"code":"invalid_grant","message":"Code ungültig, abgelaufen oder benutzt"}}}}},"403":{"description":"nicht von den Server-IPs der App","content":{"application/json":{"example":{"error":{"code":"ip_not_allowed","message":"nicht von den Server-IPs der App"}}}}}},"security":[]}},"/public/catalog":{"get":{"operationId":"public_catalog","summary":"Öffentlicher Katalog","description":"Alle Produktlinien mit Tarifen, Netto-Preisen je Laufzeit (1/3/6/12 Monate, Staffel 0/3/7/13 %), Merkmalen und Bestell-Links (order_url, seit v1.2 zusätzlich order_urls je Laufzeit), dazu Steuersätze, Betriebssysteme, Domainpreise, Kennzahlen, Status der Nodes, Netz und Links. Alle Beträge netto (*_net). Nur öffentliche Daten, ohne Schlüssel. Antwort 5 Minuten zwischengespeichert (Cache-Control, ETag; mit If-None-Match kommt 304). CORS nur für eingetragene Website-Herkünfte. Vertrag: version 1 (Erweiterungen v1.1 Info-Blöcke, v1.2 order_urls, v1.3 exchange = Angebote der KVM-Börse mit Streichpreis nur bei belegtem Normalpreis, v1.4 trial = Testserver, nur wenn eingeschaltet und die Sicherheitsgruppe geprüft vorhanden ist, v1.6 links.service_bot = Einladung des Discord-Service-Bots, nur wenn eingetragen), neue Felder sind abwärtskompatibel.","tags":["Öffentlich (Website)"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"version":1,"generated_at":"2026-11-01T12:00:00+01:00","source":"whmcs","currency":{"code":"EUR","prefix":"","suffix":" €","decimals":2,"format":"de"},"tax":{"prices_are":"net","default_country":"DE","rates":{"DE":19,"AT":20}},"terms":[{"months":1,"discount_pct":0},{"months":3,"discount_pct":3},{"months":6,"discount_pct":7},{"months":12,"discount_pct":13}],"groups":[{"key":"server","name":"Eigener Server"}],"lines":[{"slug":"vps","name":"VPS","group":"server","summary":"Geteilte Kerne, voller Root-Zugriff","hardware":"AMD EPYC 7763","virtualization":"KVM","location":"Frankfurt am Main","features":["Laufzeit frei wählbar: 1, 3, 6 oder 12 Monate"],"from_net":7.9,"order_url":"https://mam-jahn.de/vps","plans":[{"id":12,"name":"VPS 8","popular":false,"available":true,"specs":[{"key":"vcores","value":4},{"key":"ram","value":8,"unit":"GB"},{"key":"disk","value":120,"unit":"GB","note":"NVMe"}],"prices_net":{"1":13.9,"3":13.48,"6":12.93,"12":12.09},"setup_net":0,"order_url":"https://mam-jahn.de/cart.php?a=add&pid=12&billingcycle=monthly","order_urls":{"1":"https://mam-jahn.de/cart.php?a=add&pid=12&billingcycle=monthly","3":"https://mam-jahn.de/cart.php?a=add&pid=12&billingcycle=quarterly","6":"https://mam-jahn.de/cart.php?a=add&pid=12&billingcycle=semiannually","12":"https://mam-jahn.de/cart.php?a=add&pid=12&billingcycle=annually"}}]}],"os":[{"family":"Debian","versions":["12","13"]}],"exchange":{"about":["Jeden Abend entstehen neue Angebote aus freier Kapazität."],"next_at":"2026-11-01T20:00:00+01:00","offers":[{"id":"231","line":"ryzen","name":"Ryzen Deal #1","hardware":"AMD Ryzen 9 9950X","specs":[{"key":"vcores","value":4,"note":"geteilt"},{"key":"ram","value":8,"unit":"GB","note":"DDR5 ECC"},{"key":"disk","value":150,"unit":"GB","note":"NVMe SSD"}],"price_net":7.5,"regular_net":10,"discount_pct":25,"order_url":"https://mam-jahn.de/cart.php?a=add&pid=231&billingcycle=monthly","available":true,"until":"2026-11-01T20:00:00+01:00"}]},"trial":{"enabled":true,"hours":24,"specs":[{"key":"vcores","value":2},{"key":"ram","value":4,"unit":"GB"},{"key":"disk","value":40,"unit":"GB","note":"NVMe"}],"request_url":"https://mam-jahn.de/testen"},"domains":[{"tld":".de","register_net":4.9,"renew_net":4.9,"transfer_net":0}],"stats":{"threads":228,"ram_gb":1408,"nvme_tb":73,"services_active":62},"status":{"updated_at":"2026-11-01T11:58:00+01:00","nodes_online":5,"nodes_total":5,"cpu_pct":9,"nodes":[{"name":"EPYC 01","online":true,"cpu_pct":12}]},"network":{"asn":"AS201687","location":"Frankfurt am Main","uplinks":[{"name":"EPYC 01","gbit":20}]},"links":{"cart":"https://mam-jahn.de/cart.php?a=view","login":"https://mam-jahn.de/login","register":"https://mam-jahn.de/register.php","status":"https://mam-jahn.de/status","cancel":"https://mam-jahn.de/kuendigen","contact":"https://mam-jahn.de/contact.php","api_docs":"https://mam-jahn.de/api-docs","discord":"https://discord.gg/E9wzeKCtQr"}}}}},"429":{"description":"Zu viele Anfragen von dieser IP","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Zu viele Anfragen von dieser IP"}}}}},"503":{"description":"Daten gerade nicht verfügbar","content":{"application/json":{"example":{"error":{"code":"unavailable","message":"Daten gerade nicht verfügbar"}}}}}},"security":[]}},"/public/legal":{"get":{"operationId":"public_legal","summary":"Öffentliche Rechtstexte","description":"Anbieterangaben und die Rechtstexte Impressum, Datenschutz, AGB und Widerruf, gegliedert in Abschnitte mit reinem Text (Absätze durch Leerzeile getrennt – beim Anzeigen escapen). Ohne Schlüssel, 5 Minuten zwischengespeichert (ETag, 304), CORS wie beim Katalog.","tags":["Öffentlich (Website)"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"version":1,"updated":"2026-10-31","company":{"name":"Darkmatter IT","legal_form":"Einzelunternehmen","owner":"Vorname Nachname","address":"Straße 1, 12345 Ort, Deutschland","email":"support@kunden.mam-jahn.de","phone":"+49 …","vat_id":"DE…","brand":"MAM-JAHN"},"documents":{"impressum":{"title":"Impressum","sections":[{"title":"Anbieter (Angaben gemäß § 5 DDG)","text":"Firma: …\nInhaber: …"}]},"datenschutz":{"title":"Datenschutzerklärung","updated":"2026-10-31","sections":[{"title":"Vorbemerkung","text":"…"}]},"agb":{"title":"Allgemeine Geschäftsbedingungen (AGB)","updated":"2026-10-30","sections":[{"title":"§ 1 Vertragspartner und Geltungsbereich","text":"…"}]},"widerruf":{"title":"Widerrufsbelehrung","updated":"2026-10-30","sections":[{"title":"Widerrufsrecht","text":"…"}]}}}}}},"429":{"description":"Zu viele Anfragen von dieser IP","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"Zu viele Anfragen von dieser IP"}}}}},"503":{"description":"Daten gerade nicht verfügbar","content":{"application/json":{"example":{"error":{"code":"unavailable","message":"Daten gerade nicht verfügbar"}}}}}},"security":[]}},"/me":{"get":{"operationId":"me","summary":"Konto abrufen","description":"Name, E-Mail, Land, Währung und aktuelles Guthaben.","tags":["Konto"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"id":42,"firstname":"Max","lastname":"Muster","company":"","email":"max@example.de","country":"DE","currency":"EUR","credit":40}}}}},"x-scope":"account:read"}},"/invoices":{"get":{"operationId":"invoices","summary":"Rechnungen auflisten","description":"Rechnungen mit Bezahl-Link, neueste zuerst.","tags":["Konto"],"parameters":[{"name":"status","in":"query","required":false,"description":"Paid, Unpaid, Cancelled oder Refunded","schema":{"type":"string"},"example":"Unpaid"},{"name":"limit","in":"query","required":false,"description":"1–200, Standard 50","schema":{"type":"integer"},"example":20}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"invoices":[{"id":1290,"number":"R-2026-0412","date":"2026-10-19","due":"2026-10-19","paid":"","total":25,"status":"Unpaid","pay_url":"https://mam-jahn.de/viewinvoice.php?id=1290"}]}}}}},"x-scope":"invoices:read"}},"/credit/topup":{"post":{"operationId":"topup","summary":"Guthaben aufladen","description":"Erstellt eine Aufladungs-Rechnung. Nach der Zahlung über den Link ist der Betrag als Guthaben da.","tags":["Konto"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"Betrag in deiner Währung (Mindest- und Höchstbetrag wie im Kundenbereich)","example":25}},"required":["amount"]}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"example":{"invoice_id":1291,"amount":25,"pay_url":"https://mam-jahn.de/viewinvoice.php?id=1291"}}}},"422":{"description":"Betrag außerhalb der Grenzen","content":{"application/json":{"example":{"error":{"code":"invalid_amount","message":"Betrag außerhalb der Grenzen"}}}}},"409":{"description":"Aufladen ist abgeschaltet","content":{"application/json":{"example":{"error":{"code":"topup_disabled","message":"Aufladen ist abgeschaltet"}}}}}},"x-scope":"credit:topup"}},"/requests":{"get":{"operationId":"requests","summary":"Eigene Aufrufe","description":"Die letzten API-Aufrufe deines Kontos (30 Tage) – mit Status, IP und Dauer. Schlüssel und Passwörter werden nie gespeichert.","tags":["Konto"],"parameters":[{"name":"limit","in":"query","required":false,"description":"1–500, Standard 100","schema":{"type":"integer"},"example":50}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"requests":[{"time":"2026-10-19 11:58:02","method":"GET","path":"/v1/services","status":200,"ip":"203.0.113.10","ms":38,"key":"mjk_3f9a01c2","note":""}]}}}}},"x-scope":"account:read"}},"/products":{"get":{"operationId":"products","summary":"Produkte auflisten","description":"Alle über die API bestellbaren Produkte mit Preisen je Laufzeit.","tags":["Bestellen"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"products":[{"id":12,"name":"KVM S","group":"KVM Server","module":"mjpve","currency":"EUR","in_stock":true,"prices":{"monthly":{"price":9.9,"setup":0},"annually":{"price":99,"setup":0}}}]}}}}},"x-scope":"products:read"}},"/products/{id}":{"get":{"operationId":"product","summary":"Produkt abrufen","description":"Ein Produkt mit Optionen (configoptions, z. B. Betriebssystem) und Feldern (customfields) für die Bestellung.","tags":["Bestellen"],"parameters":[{"name":"id","in":"path","required":true,"description":"Produkt-ID","schema":{"type":"integer"},"example":12}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"id":12,"name":"KVM S","group":"KVM Server","module":"mjpve","currency":"EUR","in_stock":true,"prices":{"monthly":{"price":9.9,"setup":0}},"description":"2 vCores, 4 GB RAM, 40 GB NVMe","configoptions":[{"id":7,"name":"Betriebssystem","type":"dropdown","choices":[{"id":31,"name":"Debian 12","prices":{"monthly":{"price":0,"setup":0}}}]}],"customfields":[{"id":5,"name":"SSH Key","type":"textarea","required":false,"description":""}]}}}},"404":{"description":"Produkt nicht über die API bestellbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Produkt nicht über die API bestellbar"}}}}}},"x-scope":"products:read"}},"/orders":{"post":{"operationId":"order","summary":"Bestellen","description":"Bestellt ein Produkt und bezahlt standardmäßig mit Guthaben. Reicht das Guthaben nicht, wird nichts bestellt. Der Server wird danach automatisch eingerichtet – Stand über GET /v1/services/{id}.","tags":["Bestellen"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"product_id":{"type":"integer","description":"Produkt-ID aus GET /v1/products","example":12},"billingcycle":{"type":"string","description":"monthly, quarterly, semiannually, annually (24/36 Monate nicht mehr bestellbar)","example":"monthly"},"hostname":{"type":"string","description":"Hostname des Servers","example":"node1.example.de"},"configoptions":{"type":"object","description":"Option-ID => Auswahl-ID (bzw. Menge)","example":{"7":31}},"customfields":{"type":"object","description":"Feld-ID => Wert","example":{"5":"ssh-ed25519 AAAA… user@pc"}},"pay":{"type":"string","description":"credit (Standard) oder invoice (Rechnung offen lassen)","example":"credit"},"promocode":{"type":"string","description":"Gutscheincode","example":""},"customer_id":{"type":"integer","description":"nur Reseller: Endkunde, dem der Server zugeordnet wird","example":15}},"required":["product_id","billingcycle"]}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"example":{"order_id":512,"service_id":877,"invoice_id":1290,"total":9.9,"payment":"paid","pay_url":null,"next":"GET /v1/services/877 bis status Active, dann einmal GET /v1/services/877/credentials"}}}},"402":{"description":"Guthaben reicht nicht – nichts bestellt","content":{"application/json":{"example":{"error":{"code":"insufficient_credit","message":"Guthaben reicht nicht – nichts bestellt"}}}}},"422":{"description":"Option oder Auswahl unbekannt","content":{"application/json":{"example":{"error":{"code":"invalid_configoption","message":"Option oder Auswahl unbekannt"}}}}},"409":{"description":"nicht verfügbar","content":{"application/json":{"example":{"error":{"code":"out_of_stock","message":"nicht verfügbar"}}}}},"404":{"description":"Endkunde nicht gefunden (customer_id)","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Endkunde nicht gefunden (customer_id)"}}}}}},"x-scope":"orders:create"}},"/services":{"get":{"operationId":"services","summary":"Verträge auflisten","description":"Alle Verträge mit Status, Hostname und IPs. Schlüssel einer Partner-App sehen nur, was über die App bestellt wurde.","tags":["Verträge"],"parameters":[{"name":"customer_id","in":"query","required":false,"description":"nur Reseller: nur Verträge dieses Endkunden","schema":{"type":"integer"},"example":15}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"services":[{"id":877,"product_id":12,"product":"KVM S","module":"mjpve","status":"Active","hostname":"node1.example.de","ipv4":"203.0.113.25","ips":["2001:db8:25::1/64"],"billingcycle":"monthly","amount":9.9,"registered":"2026-10-19","next_due":"2026-11-19"}]}}}}},"x-scope":"services:read"}},"/services/{id}":{"get":{"operationId":"service","summary":"Vertrag abrufen","description":"Ein Vertrag. credentials zeigt, ob die Zugangsdaten abholbar sind: ok, fetched, expired oder none.","tags":["Verträge"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"id":877,"product":"KVM S","status":"Active","hostname":"node1.example.de","ipv4":"203.0.113.25","credentials":"ok"}}}},"404":{"description":"Vertrag nicht gefunden","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden"}}}}}},"x-scope":"services:read"}},"/services/{id}/credentials":{"get":{"operationId":"credentials","summary":"Zugangsdaten abholen","description":"IPv4, Benutzer und Root-Passwort eines über die API bestellten Servers – genau einmal und höchstens 24 Stunden nach der Einrichtung.","tags":["Verträge"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"service_id":877,"hostname":"node1.example.de","ipv4":"203.0.113.25","ipv4_all":["203.0.113.25"],"ipv6":["2001:db8:25::1/64"],"username":"root","password":"Xk7#q2…"}}}},"409":{"description":"Server noch nicht eingerichtet","content":{"application/json":{"example":{"error":{"code":"not_ready","message":"Server noch nicht eingerichtet"}}}}},"410":{"description":"Abholzeit abgelaufen","content":{"application/json":{"example":{"error":{"code":"credentials_expired","message":"Abholzeit abgelaufen"}}}}}},"x-scope":"services:credentials"}},"/services/{id}/status":{"get":{"operationId":"srv_status","summary":"Server-Status","description":"Läuft der Server? Dazu CPU, RAM, Platten, Laufzeit und ob der Gast-Agent antwortet.","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"status":"running","uptime":86400,"cpus":2,"cpu":3.4,"mem":1073741824,"maxmem":4294967296,"disk":0,"maxdisk":42949672960,"netin":1203391,"netout":893221,"agent":true,"disks":[{"mount":"/","used":6442450944,"total":42949672960}]}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/services/{id}/power":{"post":{"operationId":"srv_power","summary":"Starten, stoppen, neu starten","description":"start, shutdown (sauber herunterfahren), stop (hart aus), reboot, reset (harter Neustart). Höchstens eine Aktion alle 8 Sekunden je Server.","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","description":"start, shutdown, stop, reboot oder reset","example":"reboot"}},"required":["action"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true,"action":"reboot","upid":"UPID:n2:0012A3F1:…"}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}},"429":{"description":"zu schnell hintereinander","content":{"application/json":{"example":{"error":{"code":"too_fast","message":"zu schnell hintereinander"}}}}}},"x-scope":"services:power"}},"/services/{id}/os":{"get":{"operationId":"srv_os","summary":"Betriebssysteme und ISOs","description":"Vorlagen für die Neuinstallation (kind template) und einlegbare ISO-Dateien (kind iso) für diesen Server.","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"items":[{"key":"debian-12","kind":"template","name":"Debian 12","windows":false},{"key":"local:iso/rescue.iso","kind":"iso","name":"Rettungssystem"}]}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/services/{id}/reinstall":{"post":{"operationId":"srv_reinstall","summary":"Neu installieren","description":"Installiert das gewählte Betriebssystem neu – alle Daten auf der Systemplatte gehen verloren. Läuft im Hintergrund; Stand über GET /v1/services/{id}/jobs/{job}. Neues Passwort danach über password-reset.","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"template":{"type":"string","description":"key aus GET /v1/services/{id}/os (kind template)","example":"debian-12"},"hostname":{"type":"string","description":"Hostname nach der Installation","example":"node1.example.de"},"confirm":{"type":"string","description":"zur Sicherheit: der aktuelle Hostname des Servers","example":"node1.example.de"},"sshkey":{"type":"string","description":"öffentlicher SSH-Schlüssel (nicht bei Windows)","example":"ssh-ed25519 AAAA… user@pc"}},"required":["template","hostname","confirm"]}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"example":{"job":3051}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"es läuft schon ein Auftrag","content":{"application/json":{"example":{"error":{"code":"busy","message":"es läuft schon ein Auftrag"}}}}},"422":{"description":"Vorlage unbekannt","content":{"application/json":{"example":{"error":{"code":"invalid_template","message":"Vorlage unbekannt"}}}}}},"x-scope":"services:reinstall"}},"/services/{id}/jobs/{job}":{"get":{"operationId":"srv_job","summary":"Auftrag abfragen","description":"Stand einer Neuinstallation: queued, running, done oder error.","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877},{"name":"job","in":"path","required":true,"description":"Auftrags-ID aus reinstall","schema":{"type":"integer"},"example":3051}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"status":"running","error":""}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/services/{id}/password-reset":{"post":{"operationId":"srv_password","summary":"Root-Passwort zurücksetzen","description":"Setzt ein neues zufälliges Root-Passwort und gibt es zurück. Mit Gast-Agent sofort, sonst beim nächsten Start (reboot = true).","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"pw":"Qm4!x9…","method":"agent","reboot":false}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}},"422":{"description":"Gast-Agent nicht erreichbar","content":{"application/json":{"example":{"error":{"code":"no_agent","message":"Gast-Agent nicht erreichbar"}}}}}},"x-scope":"services:manage"}},"/services/{id}/hostname":{"post":{"operationId":"srv_hostname","summary":"Hostname ändern","description":"Ändert den Hostnamen (auch im Kundenbereich und im DNS des Servernamens).","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hostname":{"type":"string","description":"neuer Hostname","example":"node2.example.de"}},"required":["hostname"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"reboot":true}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}},"422":{"description":"Hostname ungültig","content":{"application/json":{"example":{"error":{"code":"invalid_hostname","message":"Hostname ungültig"}}}}}},"x-scope":"services:manage"}},"/services/{id}/sshkey":{"post":{"operationId":"srv_sshkey","summary":"SSH-Schlüssel hinterlegen","description":"Hinterlegt öffentliche SSH-Schlüssel per Cloud-Init (wirksam nach dem nächsten Start). Private Schlüssel erzeugen wir bewusst nicht.","tags":["Server"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"ein oder mehrere öffentliche Schlüssel, je Zeile","example":"ssh-ed25519 AAAA… user@pc"}},"required":["key"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"reboot":true}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}},"422":{"description":"Schlüssel ungültig","content":{"application/json":{"example":{"error":{"code":"invalid_sshkey","message":"Schlüssel ungültig"}}}}}},"x-scope":"services:manage"}},"/services/{id}/metrics":{"get":{"operationId":"srv_metrics","summary":"Verlauf","description":"Zeitreihen für CPU (%), RAM (Byte), Netz und Platte (Byte/s).","tags":["Messwerte"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877},{"name":"timeframe","in":"query","required":false,"description":"hour, day, week, month oder year","schema":{"type":"string"},"example":"day"}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"t":[1760868000,1760868060],"cpu":[2.1,3.4],"mem":[1073741824,1081081856],"maxmem":4294967296,"netin":[1200,900],"netout":[800,640],"diskread":[0,4096],"diskwrite":[12288,8192]}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/services/{id}/traffic":{"get":{"operationId":"srv_traffic","summary":"Traffic","description":"Verkehr der letzten 24 Stunden (Grundlage der Fair-Use-Drossel) und Verlauf in Schritten.","tags":["Messwerte"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877},{"name":"days","in":"query","required":false,"description":"1–31 Tage Verlauf, Standard 1","schema":{"type":"integer"},"example":7},{"name":"step","in":"query","required":false,"description":"Schritt in Sekunden (mind. 900), Standard 3600","schema":{"type":"integer"},"example":3600}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"last24h":{"rx":0,"tx":0,"total":5368709120},"limit_gb":1000,"throttle_mbit":100,"series":[{"t":1760868000,"rx":104857600,"tx":52428800}]}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/services/{id}/tasks":{"get":{"operationId":"srv_tasks","summary":"Letzte Aufgaben","description":"Die letzten Aufgaben des Servers (Start, Backup, Snapshot …). Mit ?upid=… den Stand einer einzelnen Aufgabe.","tags":["Messwerte"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877},{"name":"upid","in":"query","required":false,"description":"eine Aufgabe, z. B. aus backups oder power","schema":{"type":"string"},"example":"UPID:n2:0012A3F1:…"}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"tasks":[{"upid":"UPID:n2:0012A3F1:…","type":"vzdump","status":"OK","start":1760868000,"end":1760868120}]}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/services/{id}/backups":{"get":{"operationId":"bk_list","summary":"Backups auflisten","description":"Alle Backups mit Größe, Notiz, Schutz und dem Limit des Tarifs.","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"items":[{"volid":"backup:backup/vm/1203/2026-10-19T02:00:00Z","time":1760839200,"size":3221225472,"note":"vor Update","protected":false}],"limit":3}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"},"post":{"operationId":"bk_create","summary":"Backup erstellen","description":"Startet ein Backup im Hintergrund. Stand über GET /v1/services/{id}/tasks?upid=…","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"note":{"type":"string","description":"Notiz zum Backup","example":"vor Update"}}}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"example":{"upid":"UPID:n2:0012A3F1:…"}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"es läuft schon ein Backup","content":{"application/json":{"example":{"error":{"code":"busy","message":"es läuft schon ein Backup"}}}}},"422":{"description":"Limit des Tarifs erreicht","content":{"application/json":{"example":{"error":{"code":"limit","message":"Limit des Tarifs erreicht"}}}}}},"x-scope":"services:backups"},"delete":{"operationId":"bk_delete","summary":"Backup löschen","description":"Löscht ein Backup (geschützte Backups vorher freigeben).","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"volid":{"type":"string","description":"volid des Backups","example":"backup:backup/vm/1203/2026-10-19T02:00:00Z"}},"required":["volid"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:backups"}},"/services/{id}/backups/restore":{"post":{"operationId":"bk_restore","summary":"Backup wiederherstellen","description":"Spielt ein Backup zurück – der aktuelle Stand wird überschrieben.","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"volid":{"type":"string","description":"volid aus GET /v1/services/{id}/backups","example":"backup:backup/vm/1203/2026-10-19T02:00:00Z"}},"required":["volid"]}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"example":{"upid":"UPID:n2:0012B001:…"}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:backups"}},"/services/{id}/snapshots":{"get":{"operationId":"sn_list","summary":"Snapshots auflisten","description":"Alle Snapshots, der aktuelle Stand und das Limit des Tarifs.","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"items":[{"name":"vor_update","description":"","time":1760868000,"vmstate":false}],"limit":3,"current":"vor_update"}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"},"post":{"operationId":"sn_create","summary":"Snapshot erstellen","description":"Legt einen Snapshot an (Name: Buchstaben, Ziffern, _ und -).","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name des Snapshots","example":"vor_update"},"description":{"type":"string","description":"Beschreibung","example":"vor dem Kernel-Update"}},"required":["name"]}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"example":{"upid":"UPID:n2:0012C9D0:…"}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}},"422":{"description":"Limit erreicht","content":{"application/json":{"example":{"error":{"code":"limit","message":"Limit erreicht"}}}}}},"x-scope":"services:backups"},"delete":{"operationId":"sn_delete","summary":"Snapshot löschen","description":"Löscht einen Snapshot.","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name des Snapshots","example":"vor_update"}},"required":["name"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"upid":"UPID:n2:0012D2F0:…"}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:backups"}},"/services/{id}/snapshots/rollback":{"post":{"operationId":"sn_rollback","summary":"Snapshot zurückspielen","description":"Setzt den Server auf den Snapshot zurück.","tags":["Backups & Snapshots"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name des Snapshots","example":"vor_update"}},"required":["name"]}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"example":{"upid":"UPID:n2:0012D1E4:…"}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:backups"}},"/services/{id}/network":{"get":{"operationId":"net_list","summary":"IPs und rDNS","description":"Alle IPv4/IPv6 des Servers mit Gateway und rDNS-Eintrag.","tags":["Netzwerk"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ips":[{"ip":"203.0.113.25","version":4,"gateway":"203.0.113.1","rdns":"node1.example.de","rdns_default":"static-203-0-113-25.clients.example.net"}]}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/services/{id}/rdns":{"post":{"operationId":"net_rdns","summary":"rDNS setzen","description":"Setzt den Reverse-DNS-Eintrag einer IP des Servers. Leerer Name = Standard.","tags":["Netzwerk"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ip":{"type":"string","description":"IP des Servers","example":"203.0.113.25"},"name":{"type":"string","description":"Name (FQDN)","example":"mail.example.de"}},"required":["ip","name"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}},"422":{"description":"Name ungültig","content":{"application/json":{"example":{"error":{"code":"invalid_name","message":"Name ungültig"}}}}}},"x-scope":"services:manage"}},"/services/{id}/iso":{"post":{"operationId":"net_iso","summary":"ISO einlegen / auswerfen","description":"Legt eine ISO-Datei ins virtuelle Laufwerk ein (key aus /os mit kind iso). Leer = auswerfen.","tags":["Netzwerk"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"volid":{"type":"string","description":"ISO-key oder leer zum Auswerfen","example":"local:iso/rescue.iso"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true,"reboot":false}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}},"422":{"description":"ISO unbekannt","content":{"application/json":{"example":{"error":{"code":"invalid_iso","message":"ISO unbekannt"}}}}}},"x-scope":"services:manage"}},"/services/{id}/firewall":{"get":{"operationId":"net_fw","summary":"Firewall lesen","description":"Firewall-Status, Standard-Regeln und alle Regeln des Servers.","tags":["Netzwerk"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Vertrags (Dienst), z. B. aus GET /v1/services","schema":{"type":"integer"},"example":877}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"enable":true,"policy_in":"DROP","policy_out":"ACCEPT","rules":[{"pos":0,"type":"in","action":"ACCEPT","proto":"tcp","dport":"22","source":"","comment":"SSH","enable":true}]}}}},"404":{"description":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar"}}}}},"409":{"description":"Kein Proxmox-Server oder nicht aktiv","content":{"application/json":{"example":{"error":{"code":"not_supported","message":"Kein Proxmox-Server oder nicht aktiv"}}}}}},"x-scope":"services:read"}},"/domains/check":{"get":{"operationId":"dm_check","summary":"Verfügbarkeit prüfen","description":"Ist die Domain frei? Dazu deine Preise für Registrierung, Umzug und Verlängerung (1 Jahr).","tags":["Domains"],"parameters":[{"name":"domain","in":"query","required":true,"description":"Domain mit Endung","schema":{"type":"string"},"example":"mein-projekt.de"}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"domain":"mein-projekt.de","available":true,"tld":".de","offered":true,"prices":{"register":3.51,"transfer":3.51,"renew":3.51}}}}},"422":{"description":"Domain ungültig","content":{"application/json":{"example":{"error":{"code":"invalid_domain","message":"Domain ungültig"}}}}},"429":{"description":"höchstens 30 Prüfungen je Minute","content":{"application/json":{"example":{"error":{"code":"rate_limited","message":"höchstens 30 Prüfungen je Minute"}}}}}},"x-scope":"domains:read"}},"/domains/pricing":{"get":{"operationId":"dm_pricing","summary":"Domainpreise","description":"Alle Endungen mit deinen Preisen für 1 Jahr (Registrierung, Umzug, Verlängerung).","tags":["Domains"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"currency":"EUR","tlds":[{"tld":".de","register":3.51,"transfer":3.51,"renew":3.51},{"tld":".com","register":16.6,"transfer":16.6,"renew":16.6}]}}}}},"x-scope":"domains:read"}},"/domains":{"get":{"operationId":"dm_list","summary":"Domains auflisten","description":"Alle Domains mit Status, Ablauf und Verlängerungspreis.","tags":["Domains"],"parameters":[{"name":"customer_id","in":"query","required":false,"description":"nur Reseller: nur Domains dieses Endkunden","schema":{"type":"integer"},"example":15}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"domains":[{"id":301,"domain":"mein-projekt.de","status":"Active","registered":"2026-10-19","expires":"2027-10-19","next_due":"2027-10-19","years":1,"renewal":3.51,"auto_renew":true,"registrar":"example","customer_id":15}]}}}}},"x-scope":"domains:read"},"post":{"operationId":"dm_order","summary":"Domain registrieren / umziehen","description":"Bestellt die Domain und bezahlt mit Guthaben. Reicht es nicht, wird nichts bestellt.","tags":["Domains"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"Domain mit Endung","example":"mein-projekt.de"},"type":{"type":"string","description":"register (Standard) oder transfer","example":"register"},"years":{"type":"integer","description":"1–10 Jahre, Standard 1","example":1},"authcode":{"type":"string","description":"nur bei transfer","example":""},"nameservers":{"type":"object","description":"2–5 Nameserver als Liste","example":["ns1.example.net","ns2.example.net"]},"customer_id":{"type":"integer","description":"nur Reseller: Endkunde","example":15}},"required":["domain"]}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"example":{"order_id":513,"domain_id":301,"invoice_id":1295,"total":3.51,"payment":"paid","customer_id":15}}}},"402":{"description":"Guthaben reicht nicht","content":{"application/json":{"example":{"error":{"code":"insufficient_credit","message":"Guthaben reicht nicht"}}}}},"409":{"description":"Domain nicht frei","content":{"application/json":{"example":{"error":{"code":"not_available","message":"Domain nicht frei"}}}}},"422":{"description":"Endung/Laufzeit nicht im Angebot","content":{"application/json":{"example":{"error":{"code":"not_offered","message":"Endung/Laufzeit nicht im Angebot"}}}}}},"x-scope":"domains:order"}},"/domains/{id}":{"get":{"operationId":"dm_get","summary":"Domain abrufen","description":"Eine Domain mit aktuellen Nameservern und Transfersperre (live vom Registrar).","tags":["Domains"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID der Domain","schema":{"type":"integer"},"example":301}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"id":301,"domain":"mein-projekt.de","status":"Active","expires":"2027-10-19","nameservers":["ns1.example.net","ns2.example.net"],"locked":true}}}},"404":{"description":"Domain nicht gefunden","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Domain nicht gefunden"}}}}}},"x-scope":"domains:read"}},"/domains/{id}/nameservers":{"post":{"operationId":"dm_ns","summary":"Nameserver ändern","description":"Setzt 2 bis 5 Nameserver beim Registrar.","tags":["Domains"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID der Domain","schema":{"type":"integer"},"example":301}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nameservers":{"type":"object","description":"Liste der Nameserver","example":["ns1.example.net","ns2.example.net"]}},"required":["nameservers"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true,"nameservers":["ns1.example.net","ns2.example.net"]}}}},"422":{"description":"2–5 gültige Nameserver","content":{"application/json":{"example":{"error":{"code":"invalid_nameservers","message":"2–5 gültige Nameserver"}}}}},"502":{"description":"Registrar lehnt ab","content":{"application/json":{"example":{"error":{"code":"registrar_error","message":"Registrar lehnt ab"}}}}}},"x-scope":"domains:manage"}},"/domains/{id}/authcode":{"post":{"operationId":"dm_auth","summary":"Authcode anfordern","description":"Authcode für den Umzug zu einem anderen Anbieter. Manche Registrare schicken ihn per Mail an den Inhaber (emailed = true).","tags":["Domains"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID der Domain","schema":{"type":"integer"},"example":301}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"authcode":"Xy7-…","emailed":false}}}},"502":{"description":"Registrar lehnt ab","content":{"application/json":{"example":{"error":{"code":"registrar_error","message":"Registrar lehnt ab"}}}}}},"x-scope":"domains:manage"}},"/domains/{id}/lock":{"post":{"operationId":"dm_lock","summary":"Transfersperre","description":"Sperre ein- oder ausschalten (nicht jede Endung kennt eine Sperre).","tags":["Domains"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID der Domain","schema":{"type":"integer"},"example":301}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"locked":{"type":"boolean","description":"true oder false","example":"true"}},"required":["locked"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true,"locked":true}}}},"502":{"description":"Registrar lehnt ab","content":{"application/json":{"example":{"error":{"code":"registrar_error","message":"Registrar lehnt ab"}}}}}},"x-scope":"domains:manage"}},"/reseller":{"get":{"operationId":"rs_info","summary":"Reseller-Konto","description":"Rabatt, Guthaben, Warnschwelle und Anzahl Endkunden, Verträge und Domains.","tags":["Reseller"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"reseller":true,"group":"Reseller 15 %","discount_percent":15,"credit":240.5,"currency":"EUR","low_credit_warning":20,"customers":12,"max_customers":null,"services":31,"domains":18}}}},"403":{"description":"Konto ist kein Reseller","content":{"application/json":{"example":{"error":{"code":"not_reseller","message":"Konto ist kein Reseller"}}}}}},"x-scope":"reseller:manage"}},"/reseller/customers":{"get":{"operationId":"rs_customers","summary":"Endkunden auflisten","description":"Deine Endkunden mit Anzahl Verträge und Domains. Suche mit ?q=.","tags":["Reseller"],"parameters":[{"name":"q","in":"query","required":false,"description":"Suche in Name, Firma, Referenz, E-Mail","schema":{"type":"string"},"example":"muster"}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"customers":[{"id":15,"ref":"K-1042","name":"Max Muster","company":"Muster GmbH","email":"max@example.de","note":"","created":"2026-10-19","services":2,"domains":1}]}}}},"403":{"description":"Konto ist kein Reseller","content":{"application/json":{"example":{"error":{"code":"not_reseller","message":"Konto ist kein Reseller"}}}}}},"x-scope":"reseller:manage"},"post":{"operationId":"rs_customer_create","summary":"Endkunde anlegen","description":"Legt einen Endkunden unter deinem Konto an. Er bekommt keine Mails und keinen Zugang bei uns.","tags":["Reseller"],"parameters":[],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name (name oder company Pflicht)","example":"Max Muster"},"company":{"type":"string","description":"Firma","example":"Muster GmbH"},"ref":{"type":"string","description":"deine Kundennummer","example":"K-1042"},"email":{"type":"string","description":"E-Mail (nur für dich)","example":"max@example.de"},"note":{"type":"string","description":"Notiz","example":""}}}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"example":{"id":15,"ref":"K-1042","name":"Max Muster","company":"Muster GmbH","email":"max@example.de","note":"","created":"2026-10-19"}}}},"422":{"description":"name oder company fehlt","content":{"application/json":{"example":{"error":{"code":"missing_name","message":"name oder company fehlt"}}}}},"409":{"description":"Höchstzahl erreicht","content":{"application/json":{"example":{"error":{"code":"customer_limit","message":"Höchstzahl erreicht"}}}}}},"x-scope":"reseller:manage"}},"/reseller/customers/{id}":{"get":{"operationId":"rs_customer","summary":"Endkunde abrufen","description":"Ein Endkunde mit seinen Verträgen, Domains und Monatskosten (dein Einkaufspreis).","tags":["Reseller"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Endkunden","schema":{"type":"integer"},"example":15}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"id":15,"ref":"K-1042","name":"Max Muster","services":[{"id":877,"product":"KVM S","status":"Active","monthly":8.42}],"domains":[{"id":301,"domain":"mein-projekt.de","status":"Active"}],"monthly_cost":8.71}}}},"404":{"description":"Endkunde nicht gefunden","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Endkunde nicht gefunden"}}}}}},"x-scope":"reseller:manage"},"post":{"operationId":"rs_customer_update","summary":"Endkunde ändern","description":"Ändert nur die übergebenen Felder.","tags":["Reseller"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Endkunden","schema":{"type":"integer"},"example":15}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Name","example":"Max Muster"},"company":{"type":"string","description":"Firma","example":""},"ref":{"type":"string","description":"deine Kundennummer","example":"K-1042"},"email":{"type":"string","description":"E-Mail","example":""},"note":{"type":"string","description":"Notiz","example":"zahlt jährlich"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"id":15,"ref":"K-1042","name":"Max Muster","company":"","email":"","note":"zahlt jährlich","created":"2026-10-19"}}}},"404":{"description":"Endkunde nicht gefunden","content":{"application/json":{"example":{"error":{"code":"not_found","message":"Endkunde nicht gefunden"}}}}}},"x-scope":"reseller:manage"},"delete":{"operationId":"rs_customer_delete","summary":"Endkunde löschen","description":"Nur ohne laufende Verträge. Zuordnungen beendeter Verträge werden gelöst.","tags":["Reseller"],"parameters":[{"name":"id","in":"path","required":true,"description":"ID des Endkunden","schema":{"type":"integer"},"example":15}],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true}}}},"409":{"description":"hat noch laufende Verträge","content":{"application/json":{"example":{"error":{"code":"has_services","message":"hat noch laufende Verträge"}}}}}},"x-scope":"reseller:manage"}},"/reseller/assign":{"post":{"operationId":"rs_assign","summary":"Vertrag/Domain zuordnen","description":"Ordnet einen bestehenden Vertrag oder eine Domain einem Endkunden zu (customer_id 0 = Zuordnung lösen).","tags":["Reseller"],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"customer_id":{"type":"integer","description":"Endkunde oder 0","example":15},"service_id":{"type":"integer","description":"Vertrag (oder domain_id)","example":877},"domain_id":{"type":"integer","description":"Domain (oder service_id)","example":""}},"required":["customer_id"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"ok":true,"customer_id":15}}}},"422":{"description":"genau eins von service_id/domain_id","content":{"application/json":{"example":{"error":{"code":"invalid_target","message":"genau eins von service_id/domain_id"}}}}}},"x-scope":"reseller:manage"}},"/reseller/report":{"get":{"operationId":"rs_report","summary":"Abrechnung je Endkunde","description":"Alle laufenden Verträge und Domains je Endkunde mit deinem Einkaufspreis und Monatswert – Grundlage für deine eigene Rechnung.","tags":["Reseller"],"parameters":[],"responses":{"200":{"description":"OK","content":{"application/json":{"example":{"currency":"EUR","monthly_total":214.3,"discount_percent":15,"customers":[{"customer_id":15,"ref":"K-1042","name":"Muster GmbH","monthly_cost":8.71,"items":[{"type":"service","id":877,"name":"KVM S","hostname":"node1.example.de","amount":8.42,"billingcycle":"monthly","monthly":8.42,"next_due":"2026-11-19"}]}]}}}},"403":{"description":"Konto ist kein Reseller","content":{"application/json":{"example":{"error":{"code":"not_reseller","message":"Konto ist kein Reseller"}}}}}},"x-scope":"reseller:manage"}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"mjk_…"}}},"security":[{"bearer":[]}]}