REST-Schnittstelle¶
Nur in den Editionen Pro und Enterprise
Newsletter → Konfiguration → Module → REST-Schnittstelle
Ein Fremdsystem kann Gruppen lesen und anlegen, Abonnenten anlegen, suchen, ändern und einer Gruppe zuordnen — über HTTP, ohne zusätzliche PHP-Erweiterung.
Neu in 2.0. Seit 2.0.1 kann ein Fremdsystem auch anmelden wie ein Besucher am Formular: mit Bestätigungsmail, Einwilligungsprotokoll und allem, was dazugehört.
Sie steht neben der SOAP-Schnittstelle, nicht an deren Stelle: eigener Schalter, eigener Schlüssel, eigene Dateien. Wer SOAP abschaltet, ändert an REST nichts, und umgekehrt.
Für eine neue Anbindung ist REST die richtige Wahl.
Die Adresse¶
Sie steht auf der Modulseite. Welche Form gilt, hängt von den Permalinks Ihrer Installation ab:
mit sprechenden Permalinks https://ihre-domain.test/wp-json/wpng/v1/status
ohne https://ihre-domain.test/?rest_route=/wpng/v1/status
Ist das Modul aus, antwortet die Adresse mit rest_no_route — es wird dann
gar keine Route angemeldet.
Der Schlüssel¶
Ein eigener, nicht der von SOAP. Er entsteht beim Einschalten des Moduls aus Zufallswerten, steht als 64 Hexziffern auf der Modulseite und lässt sich dort neu erzeugen.
Eintippen kann man ihn nicht
Ein von Hand gewählter Wert wäre die eine Stelle, an der die Schnittstelle schwächer wäre, als sie aussieht.
Neuen Schlüssel erzeugen weist jede Gegenstelle ab, die noch den alten benutzt. Stimmen Sie es vorher ab.
Bei Einstellungen sichern wandert er nur mit, wenn Sie ein Kennwort vergeben — er steht in der Klasse Geheim.
Über http gehen die Inhalte im Klartext
Die Unterschrift schützt den Schlüssel, nicht die Mailadressen und Namen
im Aufruf. Die Modulseite weist darauf hin, wenn Ihre Installation nicht
über https läuft.
Für Ihre Entwickler¶
Authentisierung¶
Jeder Aufruf trägt zwei Kopfzeilen:
| Kopfzeile | Inhalt |
|---|---|
X-WPNG-Timestamp |
Unixzeit des Aufrufs |
X-WPNG-Signature |
HMAC-SHA256 in Hexziffern, klein geschrieben |
Unterschrieben wird, was den Aufruf ausmacht, mit \n getrennt:
1. HTTP-Verfahren in Großbuchstaben GET, POST
2. Route mit führendem Schrägstrich /wpng/v1/groups
3. Abfrageteil, nach Schlüsseln sortiert ohne Parameter eine leere Zeile
4. die Unixzeit aus X-WPNG-Timestamp
5. der Rumpf, Zeichen für Zeichen
Der Rumpf gehört dazu, und das ist der Punkt: Die alte SOAP-Unterschrift deckte nur die Namen der Parameter ab, nicht ihre Werte.
Zeitfenster: 900 Sekunden. Läuft die Uhr der Gegenstelle anders, sagt
GET /status die Uhrzeit der Installation.
Was die Installation selbst anhängt, zählt nicht mit. Drei
Abfrageparameter werden vor dem Unterschreiben entfernt: rest_route,
_locale und wpng_quotecheck. Alle drei hängen von der Installation ab,
nicht vom Aufrufer — stünden sie in der Unterschrift, müsste die Gegenstelle
wissen, wie Sie Ihre Permalinks eingestellt haben.
Ein Aufruf in PHP¶
$key = '…'; // der Schlüssel von der Modulseite
$basis = 'https://ihre-domain.test';
$route = '/wpng/v1/subscribers';
$rumpf = json_encode( array( 'email' => 'neu@beispiel.test' ) );
$zeit = (string) time();
$signatur = hash_hmac(
'sha256',
"POST\n" . $route . "\n" . '' . "\n" . $zeit . "\n" . $rumpf,
$key
);
$antwort = wp_remote_post(
$basis . '/wp-json' . $route,
array(
'headers' => array(
'Content-Type' => 'application/json',
'X-WPNG-Timestamp' => $zeit,
'X-WPNG-Signature' => $signatur,
),
'body' => $rumpf,
)
);
Die dritte Zeile ist der Abfrageteil. Ohne Abfrageparameter ist sie leer — der Zeilenumbruch bleibt trotzdem stehen.
Die Endpunkte¶
GET /wpng/v1/status¶
Legt nichts an und ändert nichts. Daran prüft eine frische Anbindung ihren Schlüssel und ihre Unterschrift, ohne einen Abonnenten zu hinterlassen.
{ "plugin": "wpNewsletterGermany", "version": "2.0.0", "zeit": 1789936431 }
GET /wpng/v1/groups¶
Alle Gruppen, nach Namen sortiert.
[ { "id": 1, "name": "Interessenten" }, { "id": 2, "name": "Kundennewsletter" } ]
POST /wpng/v1/groups¶
| Feld | |
|---|---|
name |
Pflicht |
201 mit { "id": 27, "name": "…" }.
Gibt es den Namen schon, ist das kein Fehler des Aufrufers, sondern ein
Konflikt: 409 mit der Kennung der vorhandenen Gruppe unter data.id. Wer
zweimal dasselbe schickt, bekommt beim zweiten Mal genug, um weiterzuarbeiten.
POST /wpng/v1/subscribers¶
| Feld | |
|---|---|
email |
Pflicht, wird geprüft |
title, vname, name, strasse, plz, ort |
optional |
status |
optional: 0 inaktiv · 1 wartet auf Bestätigung · 2 aktiv |
sendOptIn |
optional; > 0 verschickt die Bestätigungsmail |
201 mit { "id": 70, "email": "…", "status": 2 }. Der Status kommt aus der
gespeicherten Zeile, nicht aus dem Aufruf.
400 wpng_rest_email_ungueltig— die Adresse ist keine.400 wpng_rest_status_unbekannt—statusist etwas anderes als 0, 1 oder 2.409 wpng_rest_abonnent_vorhanden— Adresse gibt es schon, Kennung unterdata.id.
Anders als bei SOAP wird die Adresse geprüft, bevor etwas gespeichert wird. Eine Zeile in der Abonnententabelle, an die nie eine Mail geht, hilft niemandem.
POST /wpng/v1/subscribe¶
Seit 2.0.1. Der Weg für den Checkout eines Shops oder jedes andere Formular außerhalb des Plugins. Er meldet eine Adresse an — ob sie schon eingetragen ist oder nicht — nach genau denselben Regeln wie das Anmeldeformular.
| Feld | |
|---|---|
email |
Pflicht |
consent |
Pflicht: der Text, dem der Kunde zugestimmt hat, etwa die Beschriftung des Hakens im Checkout. Er kommt ins Einwilligungsprotokoll |
double_opt_in |
optional, Vorgabe true. false schaltet einen neuen Abonnenten direkt aktiv |
title, vname, name, strasse, plz, ort |
optional. Bei einem eingetragenen Abonnenten überschreiben sie, was dort steht; ein leeres Feld löscht nichts |
groups |
optional, Liste von Gruppenkennungen. Sie kommen dazu |
Die Antwort enthält den Abonnenten und ein Feld vorgang, das sagt, was
geschehen ist: angelegt, bestaetigung_gesendet,
bestaetigung_kuerzlich_gesendet, aktiviert, war_aktiv oder
unveraendert. 201, wenn der Abonnent neu ist, sonst 200.
consent ist Pflicht, und zwar im Wortlaut
Was hier ankommt, steht später im Einwilligungsprotokoll und ist Ihr
Nachweis. Schicken Sie den Satz, den der Kunde tatsächlich gelesen hat —
nicht „Newsletter" und nicht „true". Fehlt das Feld, antwortet die
Schnittstelle mit 400 wpng_rest_einwilligung_fehlt.
Ein abgemeldeter Abonnent wird nie still wieder aktiv
Auch nicht mit double_opt_in: false. Er bekommt die Bestätigungsmail und
ist erst nach dem Klick wieder dabei. Warum, steht unter
Das Anmeldeformular platzieren.
POST /wpng/v1/subscribers/search¶
Seit 2.0.1. Sucht einen Abonnenten über seine Adresse.
| Feld | |
|---|---|
email |
Pflicht |
200 mit dem Abonnenten, 404 wpng_rest_abonnent_fehlt, wenn es ihn nicht
gibt:
{ "id": 70, "email": "…", "status": 2, "title": "", "vname": "Rita",
"name": "Rest", "strasse": "", "plz": "", "ort": "", "groups": [ 1, 27 ] }
Warum die Adresse im Rumpf steht und nicht in der Adresszeile
Ein GET …?email=… schriebe die Mailadresse bei jedem Aufruf in das
Zugriffsprotokoll des Webservers. Im Rumpf einer POST-Anfrage bleibt sie
draußen.
POST /wpng/v1/subscribers/<id>¶
Seit 2.0.1. Ändert einen Abonnenten. PUT und PATCH gehen ebenso — POST
kommt auch bei Hostern durch, die die beiden anderen sperren.
| Feld | |
|---|---|
email |
optional, wird geprüft |
title, vname, name, strasse, plz, ort |
optional |
status |
optional: 0 inaktiv · 1 wartet auf Bestätigung · 2 aktiv |
groups |
optional, Liste von Gruppenkennungen. Sie ersetzt die bisherigen; [] nimmt den Abonnenten aus allen Gruppen |
Geändert wird nur, was im Aufruf steht. Fehlt groups, bleiben die Gruppen,
wie sie sind.
Ganz oder gar nicht
Erst wird alles geprüft, dann gespeichert. Scheitert eine Angabe, ändert sich nichts — auch nicht die Felder, die in Ordnung waren.
Hier ersetzen die Gruppen, beim Aufruf darunter kommen sie dazu. Das ist Absicht: Wer die Gruppen eines Kunden aus seinem Shop abgleicht, schickt die ganze Liste. Wer einen Abonnenten nur zusätzlich in eine Gruppe nimmt, nimmt den Aufruf darunter.
POST /wpng/v1/groups/<id>/subscribers¶
| Feld | |
|---|---|
abo |
Pflicht, Liste von Abonnentenkennungen |
{ "group_id": 27, "zugeordnet": [ 70 ], "unbekannt": [ 999999 ] }
Ein Abonnent, den es nicht gibt, lässt den Aufruf nicht scheitern — die
Antwort nennt beide Listen. Eine Gruppe, die es nicht gibt, schon:
404 wpng_rest_gruppe_fehlt.
Zugeordnet wird zusätzlich
Die bisherigen Gruppen des Abonnenten bleiben. Das ist der Unterschied zum gleichnamigen SOAP-Aufruf, der sie ersetzt.
Fehlerantworten¶
Im üblichen Format der REST-Schnittstelle von WordPress:
{ "code": "wpng_rest_signatur_falsch", "message": "…", "data": { "status": 403 } }
| Code | Status | |
|---|---|---|
wpng_rest_kein_schluessel |
503 | Das Modul läuft, aber es liegt kein Schlüssel vor |
wpng_rest_zeit_fehlt |
401 | X-WPNG-Timestamp fehlt oder ist keine Unixzeit |
wpng_rest_zeit_abgelaufen |
401 | ausserhalb des Zeitfensters |
wpng_rest_signatur_fehlt |
401 | X-WPNG-Signature fehlt oder sind keine 64 Hexziffern |
wpng_rest_signatur_falsch |
403 | die Unterschrift stimmt nicht |
Die Antwort sagt nicht, woran es genau lag, wenn die Unterschrift nicht stimmt — nur dass sie nicht stimmt. Fehlende oder abgelaufene Zeitstempel werden dagegen benannt: Das ist der Fehler, den eine neue Anbindung macht, und er ist kein Geheimnis.
Warum kein Application Password¶
Shared Hosting reicht die Kopfzeile Authorization regelmäßig nicht an
PHP durch. Die Anbindung scheiterte dann an etwas, das Sie nicht in der Hand
haben, und der Fehler sähe aus wie ein falsches Kennwort. Eigene Kopfzeilen
kommen an.
Ohne gültigen Zugang liegt die Schnittstelle still¶
Seit 2.0.1. Läuft die Testphase ab, ohne dass ein Zugangsschlüssel eingetragen
und die Adresse Ihrer Website registriert ist, stellen Anmeldeformular, Widget
und die Anbindung an wpShopGermany den Dienst ein. Die Schnittstelle
ebenso — sie antwortet dann auf jede Anfrage mit 503
wpng_rest_stillgelegt.
Was Sie dazu wissen sollten:
- Die Adressen bleiben erreichbar. Ein Endpunkt, der einfach verschwindet, sähe für die Gegenstelle aus wie ein Tippfehler. Sie bekommt eine klare Antwort und kann sie behandeln.
- Geprüft wird erst nach der Unterschrift. Wer den falschen Schlüssel schickt, bekommt weiter die Meldung dazu und erfährt nicht nebenbei, wie es um Ihren Zugang steht.
- Zu tun ist dasselbe wie überall sonst: Update-Zugang, Domain registrieren.
wpShopGermany bindet hierüber an¶
Ab der kommenden Fassung übernimmt wpShopGermany Newsletteranmeldungen aus dem Checkout über diese Schnittstelle. Damit das läuft, brauchen Sie zweierlei:
- Das Modul einschalten unter Newsletter → Konfiguration → Module → REST Schnittstelle.
- Den Schlüssel von der Modulseite in den Shop übertragen.
Wie es auf der Shop-Seite eingerichtet wird, steht im Handbuch von wpShopGermany unter Modul wpNewsletterGermany.
Was in Ihre Datenschutzerklärung muss¶
Nichts zusätzlich. Die Schnittstelle speichert keine eigenen Daten — sie legt dieselben Zeilen an, die auch das Anmeldeformular schreibt. Was darin steht, sagt Newsletter → Konfiguration → Datenerhebung.
Drei Dinge gehören trotzdem bedacht:
- Wer die Schnittstelle benutzt, bekommt Abonnentendaten zu sehen und ist damit ein Empfänger im Sinne Ihrer Datenschutzerklärung. Seit 2.0.1 kann er sie über die Suche auch lesen: Name, Anschrift, Status und Gruppen zu jeder Adresse, die er kennt.
- Läuft Ihre Website nicht über
https, gehen die Inhalte im Klartext über die Leitung. Die Unterschrift schützt den Schlüssel, nicht die Mailadressen im Rumpf. Die Modulseite weist Sie darauf hin. - Ein Abonnent, den ein Fremdsystem über
subscribersanlegt, hat kein Einwilligungsprotokoll. Der Nachweis muss dann im Fremdsystem liegen. Übersubscribeentsteht er hier — das ist der Grund, warum es diesen Endpunkt seit 2.0.1 gibt, und der bessere Weg.
