Dokumentation · Schnittstellen
API-Referenz
Lizenzprüfung, Versionsliste, Bezug von Erweiterungen — mit Feldern, Antworten und der Signatur.
Für Entwickler und Agenturen · Stand 05.10.2026
Diese Schnittstelle bedient Installationen von red.WaWi, red.Shop, red.POS und red.WMS. Sie ist öffentlicher Vertrag: Felder dürfen dazukommen, keines verschwindet und keines wechselt seine Bedeutung. Wer heute einen Client baut, baut gegen die endgültige Fläche.
Alles hier ist ohne Zugangsdaten lesbar — bis auf den Bezug von Erweiterungen, der einen Lizenzschlüssel verlangt.
Adresse #
https://api.red-commerce.com/api/v1/…
Diese Adresse zieht nie um. Sie steckt nach der Auslieferung in Installationen, die niemand mehr anfasst; eine Adresse, die aus Vertriebsgründen wandert, macht sie unerreichbar. Marketing und Technik teilen sich hier keine Domain.
Die Versionsliste #
GET /api/v1/feed/{produkt}.json
| Produkte | redshop, redwawi, redpos, redwms |
| Parameter | kanal=stable (Vorgabe) oder kanal=beta |
| Antwort | 200 mit der Liste, 404 bei unbekanntem Produkt oder Kanal |
| Begrenzung | 60 Abrufe je Minute und Adresse |
{
"releases": [
{
"version": "1.1.0",
"url": "https://…/redshop-1.1.0.zip",
"php": ">=8.3",
"security": true,
"released_at": "2026-08-01"
}
]
}
Pflicht ist nur version. Unbekannte Felder übergeht ein Client — genau
deshalb dürfen welche dazukommen.
Sie nimmt nichts entgegen
Kein Lizenzschlüssel, keine Kennung der Installation, keine Version des Fragenden, kein Domainname. Mitgeschickte Parameter werden übergangen; die Antwort ist byteweise dieselbe.
Das ist keine Nachlässigkeit, sondern der Zweck der Bauweise. Eine Anfrage der Art „ich bin 1.2.0 unter shop-mueller.de, gibt es was Neues?" baut beim Hersteller ein Verzeichnis aller Installationen samt ihrem Stand auf — und das ist genau die Liste, die ein Angreifer haben will: wer eine Lücke noch offen hat. Was wir sehen, ist eine IP-Adresse und ein Zeitpunkt. Weniger geht bei keiner Verbindung.
Es wird nichts heruntergeladen
Die Liste meldet, dass es etwas gibt. Holen und Einspielen bleibt ein Schritt, den ein Mensch auslöst. Ein System, das sich selbst aktualisiert, entscheidet über eine fremde Maschine — das ist die Entscheidung des Betreibers.
Die Lizenzprüfung #
POST /api/v1/license
Content-Type: application/json
Gefragt wird einmal am Tag in einem geplanten Auftrag, nie in einer Anfrage. Sechs Versuche je Minute sind reichlich und fangen eine Installation ab, die in einer Schleife hängt.
Die Anfrage — fünf Felder, kein sechstes
{
"license_key": "RC-XXXX-XXXX-XXXX-XXXX",
"instance_id": "3f8a…",
"product": "redshop",
"version": "1.2.0",
"environment": "production"
}
| Feld | Wofür |
|---|---|
license_key |
die Lizenz, die geprüft wird |
instance_id |
eine bei der Einrichtung erzeugte Kennung. Kein Domainname, keine IP |
product |
eine der vier Produktkennungen |
version |
die laufende Fassung, damit eine Antwort zur Installation passen kann |
environment |
production oder etwas anderes. Nur production zählt in einen Tarif |
Ein sechstes Feld wird abgewiesen, nicht stillschweigend beschnitten. Datensparsamkeit, die nur im Weglassen besteht, merkt niemand, wenn sie kaputtgeht.
Die Antwort
{
"status": "active",
"stage": "ok",
"valid_until": "2026-09-10",
"grace_until": "2026-10-10",
"entitlements": ["updates", "support", "marketplace"],
"message": null,
"releases": [ … ],
"extensions": [ … ]
}
| Feld | Bedeutung |
|---|---|
status |
active oder expired |
stage |
das Einzige, was ausgewertet werden muss — siehe unten |
valid_until |
bis dahin gilt das gespeicherte Ergebnis ohne Nachfrage |
grace_until |
bis dahin gilt es mit Hinweis |
entitlements |
updates, support, marketplace |
message |
Text für das Backend, oder null |
releases |
dieselbe Liste wie oben, Kanal stable |
extensions |
worauf diese Lizenz Anspruch hat |
message kommt vom Server, damit eine Formulierung geändert werden kann, ohne
dass eine neue Produktversion nötig wird.
Ein unbekannter Schlüssel bekommt eine Antwort, keinen Fehler
200 mit status: expired, nicht 404. Eine Installation muss „der Server
sagt: beendet" von „der Server antwortet nicht" unterscheiden können — und
Letzteres darf nie wirken. Ein 404 wäre für sie ein Ausfall: Sie liefe
unbefristet weiter, und niemand erführe je, dass der Schlüssel falsch ist.
stage — und warum der Client die Stufen nicht nachbaut
| Stufe | Was das Produkt tut |
|---|---|
ok |
nichts |
hinweis |
Hinweis im Backend, nur für Administratoren — an der Kasse und im Lager sieht ihn niemand |
kein_bezug |
keine neuen Versionen, kein neuer Bezug von Erweiterungen. Sicherheitsupdates laufen weiter |
beendet |
Das Nutzungsrecht endet rechtlich. Die Installation läuft weiter |
Wer die Stufen aus Verzugstagen selbst nachrechnet, hat sie beim nächsten Vertrag falsch. Der Server entscheidet, das Produkt führt aus.
Was in keiner Stufe passiert
Bestellannahme aussetzen. Kasse sperren. Daten zurückhalten. Backend verriegeln. Drosseln.
Was ein Betrieb schon verkauft hat, bleibt sein Geschäft. Ein Shop, der wegen einer abgelaufenen Lizenz keine Bestellungen mehr annimmt, richtet einen Schaden an, der in keinem Verhältnis zur ausstehenden Rechnung steht — und er trifft die Kunden des Betreibers, nicht ihn.
Es gibt keinen Schalter, der einen fremden Betrieb lahmlegen kann. Auch nicht für uns.
Erweiterungen #
Die Lizenzantwort nennt unter extensions, worauf Anspruch besteht:
{
"identifier": "redshop/plugin-versandrechner",
"kind": "plugin",
"version": "1.2.0",
"url": "https://api.red-commerce.com/api/v1/extension/redshop/plugin-versandrechner/1.2.0.zip",
"sha256": "9f2c…",
"size": 24680,
"security": false,
"released_at": "2026-08-13",
"requires_product": "^1.2"
}
Die Adresse reist mit. Wer sie aus Kennung und Nummer selbst baut, baut sie beim nächsten Formatwechsel falsch — und das fällt erst auf fremden Maschinen auf. Sie trägt kein Geheimnis und darf in einem Protokoll stehen.
requires_product wird in der Installation ausgewertet, nicht hier: Der
Server kennt nur die Version, die zuletzt gemeldet wurde, und die kann seit der
letzten Meldung eine andere sein.
Der Bezug
GET /api/v1/extension/{anbieter}/{paket}/{version}.zip
X-License-Key: RC-XXXX-XXXX-XXXX-XXXX
X-Instance-Id: 3f8a… (freiwillig, für die Auskunft im Kundencenter)
X-Environment: production (freiwillig)
Der Schlüssel reist im Kopf, nicht in der Adresse. Eine Adresse steht im Zugriffsprotokoll jedes Zwischenstücks, im Verlauf des Browsers und im Referrer der nächsten Anfrage; ein Lizenzschlüssel gehört in keines davon.
| Antwort | wann |
|---|---|
200 |
das Archiv |
401 |
kein X-License-Key |
403 |
Schlüssel unbekannt, kein Anspruch, oder die Stufe lässt es nicht zu |
404 |
diese Erweiterung oder diese Version gibt es nicht |
Zum Archiv gehören zwei Prüfungen, beide vor dem Entpacken: sha256 sagt
„heil angekommen", die Signatur sagt „von uns".
Die Signatur #
Jede Antwort — Versionsliste, Lizenzprüfung, Archiv — trägt drei Kopfzeilen:
X-RedCommerce-Signature: <base64>
X-RedCommerce-Key: p1
X-RedCommerce-Algorithm: ed25519
Unterschrieben wird über die Bytes des Rumpfes, nicht über eine aufbereitete Fassung davon. Wer sie prüft, prüft genau das, was er gelesen hat. Wer sie nicht kennt, übergeht die Kopfzeilen — deshalb konnte die Signatur eingeführt werden, ohne einen einzigen Client zu brechen.
Der öffentliche Schlüssel
Kennung: p1
ed25519, base64: DCU/iqP8/yqvmN/szHHNZ8QIAekisDfUPgsQR6UeNKo=
Er wird mit dem Produkt ausgeliefert und nie über diese Schnittstelle bezogen. Einen Schlüssel über denselben Kanal zu holen, den er absichern soll, sichert nichts.
Sehen Sie mehrere Kennungen vor. Ein Wechsel muss möglich sein, ohne dass eine Installation stehenbleibt, die seit acht Monaten niemand angefasst hat — und eine unbekannte Kennung ist ein eigener Fall mit eigener Meldung, nicht „Signatur falsch".
$traegt = sodium_crypto_sign_verify_detached(
base64_decode($kopf['X-RedCommerce-Signature']),
$rumpf,
base64_decode($bekannteSchluessel[$kopf['X-RedCommerce-Key']]),
);
Vier Zusagen, die wir von hier aus nicht durchsetzen können #
Sie stehen hier, damit sie beim Bau eines Clients nicht verlorengehen.
- Offline läuft weiter. Kein Aufruf je Anfrage. Geprüft wird einmal am Tag in einem geplanten Auftrag, das Ergebnis wird gespeichert, die Oberfläche liest nur.
- Antwortet der Server nicht, gilt das letzte Ergebnis unbefristet weiter. Ein Ausfall hier ist unser Problem, nicht das des Betriebs.
- Ein Fehlschlag wird festgehalten, nicht verschluckt. Ein Betreiber, dessen System seit vier Monaten nicht mehr nachsehen kann, soll das sehen — sonst hält er das Schweigen für „alles aktuell".
- Was der Server sieht, sieht der Kunde. Die fünf Felder der Anfrage stehen im Kundencenter im Klartext, mit dem Datum der letzten Meldung.
Etwas stimmt nicht oder fehlt? Melden Sie es — auch Lücken in der Dokumentation sind Fehler. Alle Anleitungen stehen unter Dokumentation.