POS API · Legacy
POS API · Legacy
Abgelöste POS-Dokumentation.
http://pos.dev.qnips.com/apiMobile Payment
Grundlagen & vollständige Einführung
Mobile Payment
In der menio App sind mehrere Zahlungsdienste eingebunden, über welche eine bargeldlose Bezahlung über das Smartphone möglich ist. Dabei ist menio selbst kein Zahlungsdienstleister, sondern nur ein Mediator mit einer einheitlichen Schnittstelle zum Abwickeln einer mobilen Zahlung.
Um eine mobile Zahlung anzustoßen, muss die Kasse einen Payment Identifier (PID) generieren und einen Zahlungswunsch inkl. Währung + Betrag unter Nutzung dieser PID beim menio System einreichen. Weiterhin ist der PID als Trigger für den Start des Bezahlprozesses in der menio App (z.B. als QrCode, NFC- oder BLE-Signal) auszugeben. Sobald die App den PID erkennt, wird der Bezahlprozess gestartet. Jede Zustandsänderung des Zahlungswunsches wird an die Kasse zurückgegeben.
Zur Zeit eingebundene Zahlungsdienstleister sind:
| Anbieter | Zahlart | Rückerstattung |
|---|---|---|
| kesh | Prepaid | nein |
| PayPal | Postpaid | nein |
weitere werden folgen. blabla
Begrifflichkeiten
Zahlungswunsch (Payment)
Um eine mobile Zahlung über das Smartphone zu initiieren, muss die Kasse einen Zahlungswunsch über die menio-API in unserem System unter Nutzung eines eindeutigen Payment Identifiers (PID) einreichen. Sobald die menio-App den PID erkennt (z.B. über einen QrCode-Scan oder über ein BLE-Signal), startet sie die Bezahlfunktion auf dem Smartphone.
Ein Zahlungswunsch besteht aus folgenden Angaben:
| Name | Typ | Bedeutung |
|---|---|---|
| qtid | string | Der Identifier der Transaktion auf welche sich dieser Zahlungswunsch bezieht |
| currency | string | Währungskennung laut ISO 4217-Spezifikation (z.B. "EUR") |
| total_value | decimal | Gesamtbetrag, der vom menio-Nutzer einzuziehen ist inkl. eventueller Trinkgelder und aller Steuer |
| included_vat | decimal | Mehrwertsteuer-Anteil im Gesamtbetrag |
| included_tip | decimal, optional | Eventuell in der Kasse eingegebenes Trinkgeldanteil im Gesamtbetrag |
| allowed_payment_providers | string, optional | Die menio App listet in der Bezahlansicht standardmäßig alle in der aktuellen Filiale eingerichteten Zahlungswege auf. Möchte die Kasse bei bestimmten Nutzern bestimmte Zahlungswege sperren, so isthier eine kommaseparierte Liste der IDs der Zahlungsproviders anzugeben, die für diesen einen Zahlungswunsch erlaubt sein sollen |
Payment Identifier (PID)
Darunter ist eine von der Kassensoftware erzeugte ID gemeint, unter welcher der Zahlungswunsch im menio-Backend eingereicht und getrackt wird. Der PID kann nach beliebigem Algorithmus erzeugt werden und muss lediglich folgenden Anforderungen entsprechen:
kann nur aus Nummern und lateinischen Groß- und Kleinbuchstaben bestehen (keine Umlaute, keine Sonderzeichen)
darf minimal 5 und maximal 20 Zeichen lang sein
muss über die gesamte Einsatzzeit einer Kasse unter demselben QnipsPOSIdentifier eindeutig sein.
menio Transaction Identifier (QTID)
Was der PID für den Zahlungswunsch ist, ist der QTID für die Transaktion (siehe dazu Kapitel 'referenz setzen'). Damit menio im Webportal den Zahlungsvorgang mit einer Transaktion verlinkt anzeigen kann, muss ein Zahlungswunsch mit dem Transaktionsdatensatz über das Setzen des QTID-Feldes auf dem Zahlungswunsch verbunden werden.
Zustände des Zahlungswunsches (Payment.State)
| Name | Bedeutung |
|---|---|
Submitted |
Zahlungswunsch ist im menio-System erfasst und wartet darauf, auf dem Smartphone gestartet zu werden. Ausschließlich Bezahlvorgänge in diesem Zustand können noch vom Submitter zurückgezogen werden |
InProcess |
Sobald der User in der menio-App den Zahlungsdienstleister ausgewählt hat, sich ihm gegenüber authentifiziert hat und die App bereit ist, den Zahlungswunsch an den Zahlungsdienstleister zu übergeben, wird der Zahlungswunsch auf den Zustand 'InPayment' gesetzt und kann von der Kasse nicht mehr abgebrochen werden |
CancelledByUser |
Wird gesetzt, wenn der Zahlungswunsch vom Nutzer in der menio-App vollständig abgebrochen wurde. Die menio-App kann diesen Zahlungswunsch allerdings wiederaufnehmen (z.B. durch erneuten Scan des QrCodes mit dem selben PID), solange der Zahlungswunsch nicht vom Submitter beendet wird oder in den Zustand Expired wechselt. |
CancelledBySubmitter |
Wird gesetzt, wenn der Erzeuger (Submitter) des Zahlungswunsches diesen über einen DELETE-Call auf die payments-Resource explizit abbricht. Das geht nur solange der Zahlungswunsch im Zustand Submitted ist. Zahlungswünsch mit diesem Zustand können keine Bezahlfunktion in der menio-App mehr auslösen. |
Succeeded |
Wird gesetzt, sobald der gewählte Zahlungsdienstleister uns einen erfolgreichen Geldtransfer meldet |
Refunded |
Wird gesetzt, wenn der Erzeuger (Submitter) des Zahlungswunsches über einen expliziten POST-Call auf die Refund-Resource eine Rückerstattung beantragt und diese uns vom Zahlungsdienstleister als erfolgt gemeldet wird |
Expired |
Jeder in unserem System erzeugte Zahlungswunsch, der nach Ablauf von 30 Minuten immer noch den Zustand Submitted hat, wird automatisch auf den Zustand Expired gesetzt und gilt ab da für die menio-App als nicht existent. Eine Wiederaufnahme des zuvor vom User abgebrochenen Zahlungswunsches verlängert diesen Timeout nicht |
PaymentProviderTransactionId
menio selbst ist kein Zahlungsdienstleister, sondern eine Wallet, die unterschiedliche Zahlungsdienstleister (wie PayPal, kesh, etc.) in einer App vereint. Die eigentliche Zahlung wird also von nachgeschalteten Providern abgewickelt. Daher bekommt jeder Zahlungswunsch nach einem erfolgreichen Geldtransfer durch den vom menio-App-Nutzer gewählten Provider, eine Provider-spezifische TransaktionsID, welche wir zur besseren Nachvollziehbarkeit an den Erzeuger des Zahlungswunsches (i.d.R. die Kassensoftware) als PaymentProviderTransactionId weiterreichen.
Discounts
Eine über die menio-API initiierte Zahlung kann optional automatisch um das für die verknüpfte Transaktion evtl. errechnete menio-Cashback reduziert werden. Ist die Funktion vom Kunden gewünscht, wird menio den Zahlbetrag eines mobilen Zahlungswunsches ggf. automatisch um das für die mit dem Zahlungswunsch verknüpfte Transaktion errechnete Cashback reduzieren und den reduzierten Zahlbetrag über den Payment Provider abwickeln. Als Nachweis gegenüber dem Finanzamt für die Korrektheit des Preisnachlasses wird in dem Feld Discount die Information über das angefallene Cashback abgespeichert und auf Anfrage an die Kassensoftware ausgeliefert. Die Kasse ist dann in der Pflicht, diesen Datensatz gemäß eigener Richtlinien für angewandte Preisnachlässe als Bestandteil der Transaktion abzuspeichern.
Erzeugung des Zahlungswunsches
Generieren Sie einen PaymentIdentifier (PID) , der den oben beschriebenen Kriterien entspricht und reichen Sie den Zahlungswunsch unter Nutzung dieser PID mit mindestens dem QTID, dem Betrag, der Währung und der PaymentTerminalId mit einem POST-Call auf die payments-Resource bei uns ein.
Beachten Sie bitte, dass zu diesem Zeitpunkt der Transaktionsdatensatz, auf den sich der aktuelle Zahlungswunsch bezieht, schon bei uns im System hinterlegt sein sollte
Damit ein QR-Code als Trigger für die Bezahlfunktion dienen kann, muss der PID eines Zahlungswunsches in den QR-Code gepackt werden. Erzeugen Sie dazu einen QrCode mit folgendem Inhalt: http:// app.qnips.com/tt/{TransactionSubmitterId}/{QTID}{PZ1}/{PID}{PZ2}, wobei:
Name Bedeutung TransactionSubmitterId der Identifier, den die Kasse bei der Aktivierung am menio-Backend zugewiesen bekommen hat QTID menio Transaction Identifier mit dem der Transaktionsdatensatz eingereicht wurde PZ1 Prüfsumme für QTID, deren Berechnungslogik in Prüfzifferberechnung beschrieben ist PID Payment Identifer PZ2 Prüfsumme für PID, deren Berechnungslogik in Prüfzifferberechnung beschrieben ist
Abbruch des Zahlungswunsches
Ein Zahlungswunsch kann durch die Kasse solange zurückgenommen werden, bis die menio App eine nicht mehr terminierbare Zahlungsanfrage an den vom Nutzer in der App ausgewählten Payment Provider übermittelt wurde. Um einen Zahlungswunsch durch die Kasse zurückzunehmen, führen Sie einen DELETE-Call auf die payments-Resource aus.
Werten Sie hiernach unbedingt den Response aus, denn dieser enthält die Information, ob dem Abbruchwunsch entsprochen werden konnte, oder nicht, weil z.B. eine Zahlung gerade im Gange oder bereits erfolgt ist.
Zustandsabfrage zum Zahlungswunsch
Nach der Übermittlung des Zahlungswunsches muss die Kasse für jeden Zahlungswunsch eine Zustandsüberwachung implementieren, bis eines der folgenden Zustände erreicht worden ist:
Confirmed - Geldtransfer hat stattgefunden
Expired - Zahlungswunsch ist abgelaufen und wird von der menio App nie mehr verarbeitet werden
CancelledByUser oder CancelledBySubmitter - Zahlungswunsch wurde abgebrochen.
Liefert ein Payment Provider für eine Bezahlanweisung eine Mißerfolgsmeldung (z.B. "Konto nicht gedeckt" o.ä.), reicht menio solche Zwischenzustände bewusst nicht an die Kasse weiter. Statt dessen wird dem Nutzer in der menio App die Möglichkeit gegeben, die Bezahlung erneut, ggf. über einen anderen Zahlungsdienst zu veranlassen bis die Zahlung entweder erfolgreich durchläuft oder der Nutzer den Bezahlprozess aktiv abbricht.
Für die Zustandsüberwachung existieren grundsätzlich zwei Möglichkeiten:
Eine Pull-Abfrage für einen bestimmten PID oder für eine Liste von PIDs (siehe dazu den GET-Call auf die paymentstates-Resource)
Eine direkte Push-Notification über einen WebSocket. Siehe dazu Kapitel menio-Websocket. In diesem Fall wird menio bei jedem Zustandswechsel eines PIDs eine direkte Benachrichtigung an die entsprechenden Subscriber versenden, die in der Kasse nach Möglichkeit asynchron verarbeitet werden sollen.
Generell empfehlen wir für den Empfang zwei Wege zu implementieren:
- Eine permanente Verbindung mit dem Websocket aufbauen, um asynchron auf Zahlungsbestätigungen zu warten und beim ankommen der Bestätigung eine visuell sichtbare Meldung über den Zahlungserfolg an den Kellner zu erzeugen.
- Zusätzlich in der Kassensoftware einen Button oder Menüeintrag einbauen, mit dem über einen GET-Call aktiv der Zustand einer Zahlungsanforderung im menio System abgefragt werden kann.
Beiden Wegen ist es jedoch gemein, dass die Zustände der Zahlungswünsche in einem einheitlichen Format geliefert werden, nämlich folgendem:
| Name | Typ | Bedeutung |
|---|---|---|
| payment_terminal_id | string | Sind in einer Filiale mehrere Plätze installiert, die mit dem selben QnipsPOSIdentifier arbeiten und über die eine Zahlung veranlasst werden kann (z.B. in einem Client-Server-Verbund), so muss für einen Zahlungswunsch ein Identifier des genauen Platzes angegeben werden, der den Zahlungswunsch angelegt hat. Dadurch kann sichergestellt werden, dass jede Zustandsmeldung zum Zahlungswunsch genau dem Platz zugeordnet werden kann, an dem der Zahlungswunsch erzeugt wurde |
| currency | string | Währungskennung laut ISO 4217-Spezifikation (z.B. "EUR") |
| total_value | decimal | Gesamtbetrag, der vom menio-Nutzer einzuziehen ist bzw. eingezogen wurde inkl. eventueller Trinkgelder und aller Steuer. ACHTUNG: Der Betrag kann nach erfolgter Zahlung größer ausfallen, als der von der Kasse eingereichte Wert, da hier u.U. ein vom menio App Nutzer bestimmtes Trinkgeld hinzukommen kann |
| included_vat | decimal | Mehrwertsteuer-Anteil im Gesamtbetrag |
| included_tip | decimal, optional | Eventuell in der Kasse eingegebenes Trinkgeldanteil im Gesamtbetrag. Ist das Trinkgeld nicht durch die Kasse angegeben, kann der menio Nutzer u.U. eigenes Trinkgeld in der menio App hinzunehmen. Daher kann der Wert hier nach erfolgter Zahlung ggf. von dem Wert abweichen, der in diesem Feld bei der Erstellung eines Zahlungswunsches angegeben wurde. |
| qtid | string | Der Identifier der Transaktion auf welche sich dieser Zahlungswunsch bezieht |
| state | string | Einer der unter Zustände des Zahlungswunsches beschriebenen Zustände |
| is_refundable | boolean | Nur gesetzt wenn state = Succeeded oder Refunded. Gibt an, ob der Betrag nach erfolgter Zahlung über den verwendeten Zahlungsdienstleisters elektronisch zurückerstattbar ist. Dies ist nicht bei allen Zahlungsdienstleistern der Fall |
| pp_id | number | Nur gesetzt wenn state = Succeeded oder Refunded. Feste, von menio vergebene Id eines Zahlungsdienstleisters (oder kurz pp für payment provider). Mögliche Werte sind: 1=PayPal, 2=kesh. |
| pp_transaction_id | string | Nur gesetzt wenn state = Succeeded oder Refunded. Das ist die ID, unter welcher der Zahlungsvorgang im System des gewählten Zahlungsdienstleisters geführt wird. |
| discount | object | Nur gesetzt wenn state = Succeeded oder Refunded. Ist vom Kunden eine direkte Verrechnung eventueller Cashbacks mit dem Zahlbetrag gewünscht, wird hier der Discount-Betrag und der Mehrwertsteueranteil darin ausgewiesen sofern die mit diesem Zahlungswunsch verknüpfte Transaktion Cashbacks erzeugt hat. |
Rücküberweisung
Bei einer Rücküberweisung wird das Geld, das im Kontext einer mobilen Zahlung über das menio System auf das Empfängerkonto transferiert wurde, wieder vom Empfängerkonto abgebucht und auf das Konto des ursprünglichen Zahlers überwiesen. Damit reduziert der Zahlungsdienstleister für sich die Betrungsmöglichkeiten und kann i.d.R. somit günstigere Transaktionspreise anbieten.
Leider wird diese Möglichkeit nicht von jedem Zahlungsdienstleister unterstützt. Daher wird menio bei der Meldung einer erfolgreichen Zahlung an die Kasse immer auch die Angabe im Feld "IsRefundable" liefern, ob für diese Zahlung eine elektronische Rücküberweisung möglich ist. Speichern Sie daher bitte bei jeder ankommenden Zahlungsbestätigung diese Information und bieten Sie die Rückerstattung auf dem User Interface nur für solche Zahlungen an, bei welchen IsRefundable = true ist.
Um eine Rücküberweisung zu veranlassen, führen Sie bitte einen POST-Call auf die refunds-resource aus.
menio-Websocket
Die von uns empfohlene Variante zum Empfang der Zahlungsbestätigungen ist über einen Websocket.
„Das WebSocket-Protokoll ist ein auf TCP basierendes Netzwerk¬protokoll, das entworfen wurde, um eine bidirektionale Verbindung zwischen einer (Web-) Anwendung und einem WebSocket-Server bzw. einem Web-Server, der auch WebSockets unterstützt, herzustellen.“ - Zitat Wikipedia (http://de.wikipedia.org/wiki/WebSocket).
Ein weiterer Vorteil eines Websockets ist, dass es, obwohl das Protokoll noch sehr jung ist, eine vielzahl der Client-Libs für unterschiedlichste Programmierplattformen und Programmiersprachen gibt. Hier eine kleine Übersicht:
.NET (2.0, 3.5, 4.0, Mono, Silverlight, WindowsPhone): http://websocket4net.codeplex.com/
Javascript (WebSocket-Klasse in den Browser-Engines): siehe Unterkapitel “Browser-Implementierungen” unter http://de.wikipedia.org/wiki/WebSocket
Delphi (basierend auf Indy 10): http://websockets.esegece.com
C (Windows, Linux) http://www.zaphoyd.com/websocketpp/ http://www.aspl.es/nopoll/
Unser Websocket funktioniert nach dem Publish/Subscribe-Prinzip. D.h. es bietet mehrere Kanäle an, auf denen Informationen zum Client gepusht werden sollen. Hier ist ausschließlich der Kanal „payment“ interessant. Das Websocket liegt auf „wss://pos.dev.qnips.com/qnipsws“. Nachfolgend ein einfaches Beispiel in Javascript, welches eine Subscription auf dem Payment-Kanal eingeht und auf Zahlungsbestätigungen reagiert.
qnipsWebsocket = function () {
var ws = new WebSocket('wss://pos.dev.qnips.com/qnipsws');
ws.onopen = function () {
var qpIdent = "abc";
wsPayments.send('{"subscribe":"payment", "qnipsposidentifier":"' + qpIdent + '"}');
};
// success
ws.onmessage = function (evt) {
console.log(evt.data);
};
// error
ws.onerror = function (evt) {
console.log(evt.message);
};
// close
ws.onclose = function () {
console.log('disconnected');
// try to reconnect each 30 seconds, until connection is established
};
};
Der Parameter ‚evt‘ der ‚onmessage‘-Funktion ist dann wie folgt aufgebaut:
{
„channel“:“payment“,
„data“:{
"payment_terminal_id":"1",
"currency": "EUR",
"total_value": 19.95,
"included_tip": 1.99,
"included_vat": 3.81,
"qtid":"af63457485af8745655cd",
"state":"1,2,3",
"is_refundable":"1,2,3",
"pp_id":1,
"pp_transaction_id":"1f7685qwef765",
"discount":{
"total_discount_value": 1.19,
"included_vat": 0.19,
}
}
}
Prüfsummenberechnung
Da bei Calls der menio-WebAPI-Resourcen die Parameter im Klartext übertragen werden, können auch bei hinreichender SSL-Verschlüsselung die Man-in-the-Middle-Angriffe nicht vollständig ausgeschlossen werden. Daher wird menio die Übertragung von sicherheitsrelevanten Parametern über eine Prüfsumme schützen, die unter Nutzung eines je Kassenplatz individuellen Geheimschlüssels auf der Kasse berechnet und im menio-Backend validiert wird.
Alle API-Calls mit mind. einer falsch angegebenen Prüfsumme werden abgewiesen.
Nun das Verfahren für die Bildung der Prüfsumme:
einen String mit
Identifier+„qPnsS14+CSSecretbilden, mit:Name Wert Identifierder Wert, für den die Prüfsumme berechnet werden soll, z.B. ein QnipsTransactionIdentifier (QTID) oder ein PaymentIdentifier (PID) „qPnsS14"ein konstanter String CSSecretder geheime Schlüssel, der je Kasse unterschiedlich ist Beispiel: Identifier=“123456“ und CSSecret=“af87b1“ ergeben
„123456qPnsS14af87b1“
- Für das Ergebnis aus vorherigem Schritt einen MD5-Hash bilden.
Für den Wert aus dem oben gezeigten Beispiel („123456qPnsS14af87b1“), würde der MD5-Hash folgender sein: 1283ff82ae8e9ace636449a519d99fa9.
Die ersten 6 Zeichen dieses Hash-Wertes bilden die Prüfsumme.
Für den bisherigen Beispiel wäre die Prüfsumme aslo 1283ff