Zum Inhalt

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.

Die Einstellungen der REST-Schnittstelle

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 — status ist etwas anderes als 0, 1 oder 2.
  • 409 wpng_rest_abonnent_vorhanden — Adresse gibt es schon, Kennung unter data.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:

  1. Das Modul einschalten unter Newsletter → Konfiguration → Module → REST Schnittstelle.
  2. 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 subscribers anlegt, hat kein Einwilligungsprotokoll. Der Nachweis muss dann im Fremdsystem liegen. Über subscribe entsteht er hier — das ist der Grund, warum es diesen Endpunkt seit 2.0.1 gibt, und der bessere Weg.