Die Kunden-API von mam-jahn.de: Produkte und Preise abfragen, mit Guthaben bestellen, Zugangsdaten abholen, Server starten, neu installieren, sichern. Jeder Schlüssel hat nur die Rechte, die du wählst – auf Wunsch nur von deinen IPs aus.
LoslegenErst mit „Sandbox“ ausprobieren – dann tut die API nur so und ändert nichts.
Schlüssel & Rechte
Ein Schlüssel, genau die Rechte, die er braucht
Jeder Aufruf schickt den Schlüssel im Header Authorization: Bearer mjk_…. Fehlt ein Recht, kommt 403 missing_scope. Ist eine IP-Liste hinterlegt, gilt der Schlüssel nur von dort (IPv4/IPv6, auch Netze wie /24 oder /64).
account:readKonto und Guthaben lesen
invoices:readRechnungen lesen
credit:topupGuthaben aufladen (Rechnung erstellen) · derzeit nicht freigegeben
products:readProdukte und Preise lesen
orders:createBestellen und mit Guthaben bezahlen · derzeit nicht freigegeben
services:readVerträge und Server lesen
services:credentialsZugangsdaten neuer Server abholen (einmalig, 24 h) · derzeit nicht freigegeben
services:powerServer starten, stoppen, neu starten · derzeit nicht freigegeben
services:backupsBackups und Snapshots anlegen, zurückspielen, löschen · derzeit nicht freigegeben
services:reinstallServer neu installieren (löscht die Systemplatte) · derzeit nicht freigegeben
domains:readDomains und Preise lesen, Verfügbarkeit prüfen · derzeit nicht freigegeben
domains:orderDomains registrieren und umziehen (mit Guthaben) · derzeit nicht freigegeben
domains:manageNameserver, Authcode, Sperre ändern · derzeit nicht freigegeben
reseller:manageReseller: Endkunden verwalten, zuordnen, Abrechnung · derzeit nicht freigegeben
Fehler & Status
Klare Codes statt Rätselraten
Fehler kommen immer als {"error":{"code":"…","message":"…"}} – code ist fest, message ist für Menschen.
200 / 201 / 202
OK, angelegt, im Hintergrund gestartet
401
Schlüssel fehlt, falsch, widerrufen oder abgelaufen
402
Guthaben reicht nicht – nichts bestellt
403
Recht fehlt oder IP nicht erlaubt
404 / 405
unbekannt oder falsche Methode
409 / 410
gerade nicht möglich · schon abgeholt bzw. abgelaufen
422
Eingabe ungültig
429
zu viele Aufrufe – kurz warten
502 / 503
Server-Plattform antwortet nicht · API abgeschaltet
Sandbox
Ausprobieren, ohne etwas zu ändern
Mit dem Header X-MJ-Sandbox: 1 prüft die API Schlüssel, Rechte, IP und Bremse wie immer – führt aber nichts aus und antwortet mit dem Beispiel aus dieser Doku. Kein Server wird bestellt, neu installiert oder gelöscht. Der Schalter oben rechts setzt den Header für „Anfrage testen“.
Partner-Apps
„Mit mam-jahn verbinden“ in deiner App
App anmeldenWir legen deine App an: Name, Rücksprung-Adresse, Server-IPs, optional Webhook. Du bekommst Client-ID, Client-Secret und Webhook-Secret.
Code tauschenDer Kunde bestätigt und kommt mit ?code=…&state=… zurück. Dein Server tauscht den Code mit POST /oauth/token gegen einen Schlüssel nur für diesen Kunden. App-Schlüssel sehen nur Server, die über die App bestellt wurden.
Webhook service.readyZugangsdaten eines neuen Servers, genau einmal. Prüfen: X-MJ-Signature = HMAC-SHA256(X-MJ-Timestamp + "." + body, webhook-secret)
Allgemein
Schlüssel prüfen und die maschinenlesbare Beschreibung.
GET/ping
Schlüssel prüfen
Antwortet mit Kunden-ID und den Rechten des Schlüssels – ideal für einen ersten Test.
jeder Schlüssel200
Mögliche Fehler
401
unauthorized Schlüssel fehlt, ist falsch oder widerrufen
403
ip_not_allowed Aufruf von einer nicht erlaubten IP
403
account_email E-Mail des Kontoinhabers nicht bestätigt
403
account_approval Neukunde, API noch nicht freigeschaltet
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.
ohne Schlüssel200nur Partner-Apps
Parameter
grant_typeBody · Text · Pflicht
immer authorization_code
codeBody · Text · Pflicht
Code aus dem Rücksprung
client_idBody · Text · Pflicht
Client-ID der App
client_secretBody · Text · Pflicht
Client-Secret der App
redirect_uriBody · Text · Pflicht
dieselbe Rücksprung-Adresse wie beim Verbinden
Mögliche Fehler
401
invalid_client Client-ID oder Secret falsch
400
invalid_grant Code ungültig, abgelaufen oder benutzt
Katalog, Preise, Steuersätze, Status und Rechtstexte für Websites – ohne Schlüssel, nur öffentliche Daten.
GET/public/catalog
Öffentlicher Katalog
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.
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.
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}.
orders:create201
Parameter
product_idBody · Zahl · Pflicht
Produkt-ID aus GET /v1/products
billingcycleBody · Text · Pflicht
monthly, quarterly, semiannually, annually (24/36 Monate nicht mehr bestellbar)
hostnameBody · Text
Hostname des Servers
configoptionsBody · Objekt
Option-ID => Auswahl-ID (bzw. Menge)
customfieldsBody · Objekt
Feld-ID => Wert
payBody · Text
credit (Standard) oder invoice (Rechnung offen lassen)
promocodeBody · Text
Gutscheincode
customer_idBody · Zahl
nur Reseller: Endkunde, dem der Server zugeordnet wird
Mögliche Fehler
402
insufficient_credit Guthaben reicht nicht – nichts bestellt
422
invalid_billingcycle Laufzeit nicht angeboten
422
invalid_configoption Option oder Auswahl unbekannt
import os, requests
r = requests.post(
"https://mam-jahn.de/mjapi.php/v1/orders",
headers={"Authorization": f"Bearer {os.environ['MJ_KEY']}"},
json={"product_id":12,"billingcycle":"monthly","hostname":"node1.example.de","configoptions":{"7":31},"customfields":{"5":"ssh-ed25519 AAAA… user@pc"},"pay":"credit","customer_id":15},
)
data = r.json()
Antwort · 201
{
"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"
}
Verträge
Alle Verträge und die Zugangsdaten neuer Server.
GET/services
Verträge auflisten
Alle Verträge mit Status, Hostname und IPs. Schlüssel einer Partner-App sehen nur, was über die App bestellt wurde.
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.
services:reinstall202
Parameter
idPfad · Zahl · Pflicht
ID des Vertrags (Dienst), z. B. aus GET /v1/services
templateBody · Text · Pflicht
key aus GET /v1/services/{id}/os (kind template)
hostnameBody · Text · Pflicht
Hostname nach der Installation
confirmBody · Text · Pflicht
zur Sicherheit: der aktuelle Hostname des Servers
sshkeyBody · Text
öffentlicher SSH-Schlüssel (nicht bei Windows)
Mögliche Fehler
404
not_found Vertrag nicht gefunden oder für diesen Schlüssel nicht sichtbar
409
not_supported Kein Proxmox-Server oder nicht aktiv
422
confirm confirm passt nicht zum aktuellen Hostnamen