The mam-jahn.de customer API: query products and prices, order with credit, fetch credentials, start, reinstall and back up servers. Every key only has the permissions you choose – optionally only from your IPs.
GoTry with “Sandbox” first – the API then only pretends and changes nothing.
Keys & permissions
One key, exactly the permissions it needs
Every call sends the key in the header Authorization: Bearer mjk_…. A missing permission returns 403 missing_scope. If an IP list is set, the key only works from there (IPv4/IPv6, also networks such as /24 or /64).
account:readRead account and credit
invoices:readRead invoices
credit:topupTop up credit (create invoice) · currently not available
products:readRead products and prices
orders:createPlace orders paid with credit · currently not available
services:readRead services and servers
services:credentialsFetch credentials of new servers (once, 24 h) · currently not available
services:powerStart, stop, reboot servers · currently not available
services:manageConfigure servers (hostname, SSH key, password, rDNS, ISO) · currently not available
services:backupsCreate, restore, delete backups and snapshots · currently not available
services:reinstallReinstall servers (wipes the system disk) · currently not available
domains:readRead domains and prices, check availability · currently not available
domains:orderRegister and transfer domains (with credit) · currently not available
domains:manageChange nameservers, auth code, lock · currently not available
reseller:manageReseller: manage end customers, assignments, billing · currently not available
Errors & status
Clear codes, no guessing
Errors always look like {"error":{"code":"…","message":"…"}} – code is stable, message is for humans.
200 / 201 / 202
OK, created, started in the background
401
key missing, wrong, revoked or expired
402
insufficient credit – nothing ordered
403
missing permission or IP not allowed
404 / 405
unknown or wrong method
409 / 410
not possible right now · already fetched or expired
422
invalid input
429
too many calls – wait a moment
502 / 503
platform not responding · API disabled
Sandbox
Try things without changing anything
With the header X-MJ-Sandbox: 1 the API checks key, permissions, IP and rate limit as usual – but executes nothing and answers with the example from this documentation. Nothing is ordered, reinstalled or deleted. The switch at the top sets the header for “Try it”.
Partner apps
“Connect with mam-jahn” in your app
Register appWe register your app: name, redirect address, server IPs, optional webhook. You receive client ID, client secret and webhook secret.
Exchange codeThe customer confirms and returns with ?code=…&state=…. Your server exchanges the code via POST /oauth/token for a key for this customer only. App keys only see servers ordered via the app.
Webhook service.readyCredentials of a new server, exactly once. Verify: X-MJ-Signature = HMAC-SHA256(X-MJ-Timestamp + "." + body, webhook-secret)
General
Schlüssel prüfen und die maschinenlesbare Beschreibung.
GET/ping
Check key
Returns client ID and the key's permissions – ideal as a first test.
any key200
Possible errors
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
Partner apps only: after “Connect with mam-jahn” the customer returns with ?code=…. The app's server exchanges this code (10 minutes, once) for a key for this customer only.
no key200partner apps only
Parameters
grant_typeBody · Text · required
immer authorization_code
codeBody · Text · required
Code aus dem Rücksprung
client_idBody · Text · required
Client-ID der App
client_secretBody · Text · required
Client-Secret der App
redirect_uriBody · Text · required
dieselbe Rücksprung-Adresse wie beim Verbinden
Possible errors
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
Public catalog
All product lines with plans, net prices per term (1/3/6/12 months, tiers 0/3/7/13 %), specs and order links (order_url, since v1.2 also order_urls per term), plus tax rates, operating systems, domain prices, figures, node status, network and links. All amounts net (*_net). Public data only, no key needed. Response cached for 5 minutes (Cache-Control, ETag; 304 with If-None-Match). CORS only for registered website origins. Contract: version 1 (extensions v1.1 info blocks, v1.2 order_urls, v1.3 exchange = KVM exchange offers, strike-through price only with a documented regular price, v1.4 trial = free test server, only when enabled and the security group was checked as present, v1.6 links.service_bot = invite of the Discord service bot, only when set), new fields are backward compatible.
Provider details and the legal texts (imprint, privacy, terms, withdrawal) in sections of plain text (paragraphs separated by a blank line – escape when rendering). No key needed, cached for 5 minutes (ETag, 304), CORS as for the catalog.
Orders a product, paid with credit by default. If credit is insufficient nothing is ordered. The server is then set up automatically – check GET /v1/services/{id}.
orders:create201
Parameters
product_idBody · integer · required
Produkt-ID aus GET /v1/products
billingcycleBody · Text · required
monthly, quarterly, semiannually, annually (24/36 Monate nicht mehr bestellbar)
hostnameBody · Text
Hostname des Servers
configoptionsBody · object
Option-ID => Auswahl-ID (bzw. Menge)
customfieldsBody · object
Feld-ID => Wert
payBody · Text
credit (Standard) oder invoice (Rechnung offen lassen)
promocodeBody · Text
Gutscheincode
customer_idBody · integer
nur Reseller: Endkunde, dem der Server zugeordnet wird
Possible errors
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()
Response · 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"
}
Services
Alle Verträge und die Zugangsdaten neuer Server.
GET/services
List services
All services with status, hostname and IPs. Partner app keys only see what was ordered via the app.