FORMAT: 1A
HOST: http://pos.dev.qnips.com/api/pos/v3
# Qnips Web API v3 (draft)
Diese Seite beschreibt, wie Sie das Qnips-Funktionen in Ihre Software einbinden können. Diese Funktionen lassen sich größtenteils
unabhängig voneinander nutzen, sodass auch eine Teil-Implementierung dieser Schnittstelle durchaus Sinn macht. Schauen Sie sich
zunächst die verfügbaren Funktionsblöcke an und entscheiden Sie selbst, welche Teile davon Sie oder Ihr Kunde implementiert sehen möchte.
Dienst-Name | Beschreibung
---|---
**Direktes Feedback zum Einkauf** | Die Konsumenten können zu jedem einzelnen erworbenen Artikel nach einer Bewertung und einer Meinung gefragt werden. Ebenso ist mit dieser Funktion die Bewertung des Einkaufserlebnisses inkl. Bediener-Bewertung sowie weitere individuelle Fragen des Händlers möglich.
**Clearing von Coupon- und Treue-Kampagnen** | Ihre Software bekommt hier die genaue Auskunft über die im Qnips-System eingestellten, vielfältigen, für jede einzelne Transaktion individuell errechneten Coupon- und Treue-Aktionen, um diese direkt in Ihrer Software abspeichern und ggf. auf der Endabrechnung für den Konsumenten verrechnen zu können.
**Digitaler Kassenbon** | Da die Transaktionsdaten eines Konsumenten-Kaufs die Grundlage für unsere Funktionen darstellen, können wir jedem Konsumenten das Feature des Digitalen Bons anbieten. Damit hat er die Rechnungen jederzeit nur ein paar Klicks entfernt und kann mit diesen auch Rückgaben und Artikelumtausch abwickeln.
**Mobile Payment** | Qnips erlaubt bequeme mobile Zahlungen an Ihrem POS über diverse etablierte Zahlungsdienste.
**Kundenkarten** | Um die Vorteile der Qnips-Funktionen nicht ausschließlich den Smartphone-Nutzern vorenthalten zu müssen, können diese auch mit einer beliebig gearteten Kundenkarte (Magnetkarte, NFC-/RFID-Transponder, Barcode-/QRCode-Karten etc.) als Mittel zur Identifizierung eines Kunden-Profils und Bereitstellung der Qnips-Angebote umgesetzt werden.
**(Kunden)-Karten mit Auflade und Zahl-Funktion** | Damit können Sie Ihrer Zielgruppe (z.B. in der Gemenschaftsverpflegung) eine bequeme Zahl- bzw. Geschenkkarten-Funktion anbieten, die keine besondere Aufwerter-Hardware braucht.
Let's get started!
# Grundlegendes
## Art der Schnittstelle
Unsere API ist als REST-API realisiert. Die Clients müssen also u.U. eine Bibliothek zum Verarbeiten von HTTP-Calls (GET, POST, PUT, DELETE)
einbinden. Die Bibliothek muss in der Lage sein, dem Request spezifische Header hinzuzufügen.
## URL
URL Struktur ist folgende `https://{domain}/api/v3/{resource}/{id}[/{action}][?paramName={paramValue}]`
| Code | Beschreibung |
| --- | --- |
|`{domain}` |Für produktiven Betrieb setzen Sie hier `pos.api.qnips.com`. Zur Entwicklungszeit verwenden Sie bitte `pos.dev.qnips.com`. |
|`/api/v3/` |Das ist ein fixer Part, der die Version der Schnittstelle angibt. Sollten in Zukunft aktuellere Versionen entstehen, werden Sie gesondert dazu benachrichtigt. |
|`{resource}` |Dies spezifiziert den Typ der Datenobjekte, auf welche Sie zugreifen wollen. Unterstützte Typen sind u.a. trackingUnits, baskets, sortiments, products, purchases, tokens
|`{id}` |`id` spezifiziert die ID des speziellen Objekts, auf welchen zugegriffen werden soll. |
|`{action}` |Auf manchen Datenobjekten sind besondere Operationen möglich, die als `{action}` angegeben werden können
|`{paramValue}`|Optional sind bei manchen Calls zusätzliche URL-Parameter erforderlich, um die Aktion genauer zu spezifizieren
*Beispiel: `http://pos.dev.qnips.com/api/v3/trackingUnits/123/purchase?customerIdentToken=abc&basketId=1001` wird einen Kauf mit der Rechnungsnummer 1001 (basketId=1001) mit einem Konsumenten verknüpfen, der sich am POS mit einer Kundenkarte (token=abc) identifiziert hat.*
## XML/JSON als Datenformat
Als Formate sind XML und JSON wählbar. Dies kann über die Header 'Accept' und 'ContentType' gesteuert werden. Ohne explizite Angaben zum gewünschten Datenformat über die besagten Header
wird XML als Default-Format genommen.
## Encoding
### Encoding der Parameter
Da in der URL keine Leerzeichen, Zeilenumbrüche, Umlaute, Nicht-lateinische-Zeichen und bestimmte Sonderzeichen erlaubt sind,
müssen die Werte für bestimmte Parameter zuvor URL-escaped werden.
*Beispiel: Der String `“Kölner Treff”` müsste vor dem Call zu `“K%C3%B6lner%20Treff”` umgewandelt werden.*
### Encoding im Body
Bitte platzieren Sie im Body von Requests stets ein in `utf-8` kodiertes XML/JSON.
### Encoding im XML
Bitte beachten Sie dass im XML bestimmte Zeichen ebenfalls nicht als Werte für XML-Tags erlaubt sind, sodass auch hier ggf. ein URL-Escaping statt finden soll
*Beispiel: `Drinks&Food` müsste mindestens zu `Drinks%26Food` umgewandelt werden.*
## Status Codes
Die Responses werden immer einen der folgenden HTTP-Statuscodes enthalten.
| Code| Beschreibung |
| --- | --- |
|`200`| **Success** - Markiert die erfolgreiche Ausführung. |
|`400`| **Bad Request** - Request kann aufgrund von fehlgeschlagenen Validierungen bzw. unerfüllten Vorbedingungen nicht durchgeführt werden. Bitte verarbeiten Sie bei solchen Fehlern die ErrorId im Response-Body, da in manchen Fällen eine Wiederholung des Requests Sinn macht. |
|`401`| **Unauthorized** - DevKey, trackingUnitId oder Security-Token ist/sind gar nicht bzw. falsch angegeben. |
|`500`| **Server error** - Während der Verarbeitung ist etwas schief gelaufen. Im Body stehen idR mehr Details zum Fehler, die für Logs und Entwickler gedacht sind, sich jedoch nicht zur Ausgabe am UI eignen.|
## HTTP-Header
Jede Resource unserer API ist mit zwei speziellen obligatorischen Headern geschützt, anhand derer
einerseits der Aufrufer und andererseits der Hersteller des aufrufenden Clients identifiziert
werden.
### Obligatorische Header
| Header-Name| Beschreibung |
| --- | --- |
|`DevKey`|Hier ist Ihr DeveloperKey einzutragen, den Sie bei uns beziehen können. |
|`trackingUnitId`|Jeder einzelne Client, der die Qnips API aufrufen möchte, muss sich zunächst am Qnips System registrieren (siehe *[Client-Registrierung](#introduction/client-registrierung)*), wodurch er in den Besitz einer eindeutigen `trackingUnitId` kommt, die hier bei jedem weiteren Call anzugeben ist.|
### Optionale Header
Weiterhin gibt es einige optionale Header, mit denen z.B. das Wunschformat (JSON oder XML) für den Datenaustausch angegeben werden kann.
| Header-Name| Beschreibung |
| --- | --- |
|`Accept`| Hiermit geben Sie an, ob Sie die Ergebnisse eines Calls im XML- oder JSON-Format erwarten. Erlaubt sind `application/xml` und `application/json`. Default ist `application/xml`.|
|`Content-Type`| Hierüber geben Sie an, ob der Content im Body Ihrer POST- und PUT-Requests XML oder JSON ist. Erlaubt sind `application/xml` und `application/json`. Default ist `application/xml`.|
|`Accept-Encoding`| Zur Reduzierung des Traffics und zur Beschleunigung der Interaktion mit der QnipsAPI unterstützt diese die gezippte Übertragung der Inhalte. Wird dieser Header im Request mit **'gzip'** gesetzt, so ist der Content im Response gezippt.|
|`Content-Encoding`| Bei manchen POST-Calls ist es sinnvoll, auch den Inhalt des Request-Bodys gezippt zu übertragen. Setzen Sie in diesem Fall diesen Header mit **'gzip'**. Dadurch merkt das Backend, dass der Request gezippt ist und entzippt es vor der Verarbeitung|
|`SecurityToken`| Manche Resourcen sind zusätzlich mit einem dynamisch zu berechnenden Security-Token geschützt, um besonders sensible Teile der API zu schützen. Aus welchen Teilen des Requests ein solcher Token zu bilden ist, ist direkt bei der Spezifikation der Reource beschrieben. Der Berechnungsalgorythmus ist stets derselbe und ist [hier](#introduction/grundlegendes/secutiry-token) beschrieben.|
## Secutiry-Token
Da bei Calls der Qnips-WebAPI-Ressourcen 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 Qnips die Übertragung von sicherheitsrelevanten Parametern
über einen sog. `SecurityToken` schützen, der vor dem Request dynamisch zu berechnen und dem Request als Header beizufügen ist und im
Qnips-Backend vor der Verarbeitung des Requests validiert wird. Dieser SecurityToken ist gesichert durch:
+ einen, den dritten unbekannten, Berechnungsalgorithmus
+ einen je `trackingUnit` individuellen Geheimschlüssel (`checksumSecret`), der bei der Registrierung der trackingUnit zugewiesen wird (siehe
[GET trackingUnits](#reference/trackingunits/registrieren/get-trackingunits))
Jede, mit einem SecurityToken geschützte Resource definiert, für welche Bestandteile der Eingabeparameter ein `SecurityToken` zu bilden ist. Die
Methode zur Berechnung des SecurityTokens nimmt also einen String an und liefert den Token ebenfalls als String zurück. Hier der Algorythmus für diese Methode:
+ einen String mit `input` + `„qPnsS14“` + `checksumSecret“` bilden, mit:
+ `input`: der Wert, für den die Prüfsumme berechnet werden soll
+ `„qPnsS14“`: ein konstanter String
+ `checksumSecret`: Schlüssel, welcher der`trackingUnit` bei der Registrierung zugewiesen wurde
Beispiel mit `input`=„123456“ und `checksumSecret`=„af87b1“: **„123456qPnsS14af87b1“**
+ Für das Ergebnis aus dem esten Schritt einen MD5-Hash bilden. Für den Wert aus dem oben gezeigten Beispiel, würde der MD5-Hash folgender sein: **„1283ff82ae8e9ace636449a519d99fa9“**
+ Dieser Hash ist der `SecurityToken`. Packen Sie ihn nun in den `SecurityToken`-Header des Requests, damit der Request an unserem Backend verarbeitet werden kann.
## QR-Code-Aufbau
Ein QR-Code hat in unserem System die Aufgabe, einen Einkauf mit einem Konsumenten zu verknüpfen. Dies wird dadurch erreicht, dass
zwei Identifier in den QR-Code gepackt werden, anhand derer einerseits die ausgebende POS-Instanz und andererseits der vom Konsumenten
gekaufte Warenkorb ( `basket` ) identifiziert werden können.
Daher hat der QR-Code immer die folgende Struktur:
**“http:\\app.qnips.com\t1\\{trackingUnitId}\\{basketId}”**, wobei:
* `{trackingUnitId}` - der Identifier der POS-Instanz, an welcher der gegebene Warenkorb erstellt und erworben wurde (siehe
[GET trackingUnits](#reference/trackingunits/registrieren/get-trackingunits))
* `{basketId}` - der Identifier des Warenkorbs, unter welchem die Warenkorbdaten an unser System übermittelt worden sind (siehe
[POST baskets/{basketId}](#reference/baskets/basket-hochladen/post-baskets%2F%7Bbasketid%7D%3Fconsumeridenttoken%3D%7Btoken1%7D%26giftcardid%3D%7Btoken2%7D))
# Begriffsdefinition
Diese API-Beschreibung nutzt einige Begriffe, die wie folgt zu verstehen sind:
* **merchant (Händler)** - ein Händler ist ein durch seinen eindeutigen Namen ( *merchantName*, z.B. 'Restaurant Vier Jahreszeiten') differenzierbarer
Träger von einem oder mehreren Verkaufsstandorten (Filialen), in welchen wiederum mehrere *trackingUnits* (i.d.R. POS-Terminals) existieren können
* **trackingUnit (POS-Terminal)** - jeder POS-Terminal, welcher eine Rechnung in Ihrem POS-System erzeugen und abrechnen kann,
sollte sich als eigenständige *trackingUnit* in unserem System registrieren, damit wir jede Aktion bis auf diese trackingUnit
nachverfolgen und ggf. asynchron auftretende Ereignisse (z.B. Zahlungsbestätigung beim Mobile Payment) an genau die trackingUnit
zurückmelden können
* **store (Filiale)** - in der Regel wird ein *merchant* die meisten Vorgänge auf Filialebene nachvollziehen wollen. Daher stellen
die *stores* eine sinnvolle Gruppierungsebene für *trackingUnits*. Darüber hinaus werden die stores für Konsumenten als nach Entfernung zum eigenen Standort sortierte Filialen in der
Qnips-App dargestellt, sofern uns die Adress-Daten der stores vorliegen. Die Zuweisung der trackingUnits zu stores, sowie die Pflege
der Adressdaten der stores können sowohl automatisiert aus Ihrem System heraus, als auch vom merchant händisch über unser Web-Portal erfolgen
* **basket (Warenkorb)** - das ist ein Objekt, welches die Daten über die vom Konsumenten gekauften Positionen beinhaltet, so wie sie
im Kontext einer Rechnung in einer *trackingUnit* erfasst wurden
* **purchase (Kauf-Ereignis)** - hiermit ist eine Verlinkung eines *baskets* mit einem Konsumenten-Profil gemeint, die auf einem der
folgenden zwei Wege zustande kommen kann:
* **über QrCode** - die *trackingUnit* druckt einen QrCode auf der Rechnung ab, der vom Konsumenten abgescannt werden muss. Dadurch wird der *basket* mit dem Konsumenten-Profil des Scanners verknüpft.
* **über Konsumenten-Identifikation am POS** - diese kann auf vielerlei Wegen erfolgen, die letztendlich mit jedem Händler individuell abzustimmen sind, z.B. über das Einlesen einer Kundenkarte, oder durch das Abscannen eines Identification-QrCodes vom Bildschirm des Smartphones, oder durch die Übermittlung des Identifiers vom Smartphone über NFC etc.
* **cosumer (Kosument)** - damit ist ein Endkunde gemeint, der in einem *store* eines *merchants* einen *basket* erwirbt
und dieses Kauf-Ereignis ( *purchase* ) entweder über einen Scan des QrCodes oder über Identifikation am POS mit seinem Konsumenten-Profil im Qnips-System verknüpft
* **consumerIdentToken** - damit ist ein auf einem beliebigen Trägermedium gespeicherter, beliebig gearteter `Token` gemeint, der eindeutig
mit einem *consumer*-Profil verknüpft ist und somit dafür geeignet ist, den Konsumenten eindeutig zu identifizieren. Dieser Token kann z.B.
in einer Kundenkarte gespeichert sein, oder in Form eines gedruckten oder virtuellen Barcodes oder QrCodes existieren, der vom POS-System
entweder eingescannt oder über ein anderes Trägermedium eingelesen werden kann.
* **sortiment (Produktstamm)** - Ein Produktstamm ist eine Organisationseinheit für die vom *merchant* als Reward-fähig markierte
Verkaufsartikel, die am POS in einen *basket* gebucht werden können. Solche Artikel müssen dem Qnips-System durch einen Upload
bekannt gemacht werden, damit der *merchant* einen Reward auf diese Artikel definieren kann.
# Client-Registrierung
Jedes POS-Terminal, das eigenständig mit dem Qnips-System kommuniziert und vor allem eigenständig eine Rechnung in Ihrem POS-System
erzeugen und abrechnen kann, muss eine eindeutige `trackingUnitId` vom Qnips-System erfragen. Somit stellen wir sicher, dass der
*merchant* in der Lage ist, alle Vorgänge auf der Ebene eines einzelnen Kassenplatzes nachzuverfolgen. Dazu ist, sofern der Client
noch nicht über eine trackingUnitId verfügt, einmalig ein *[GET trackingUnits](#reference/trackingunits/registrieren/get-trackingunits)*-Call
auszuführen und das Ergebnis des Calls im Client dauerhaft zu persistieren.
## Standort-Bezug einer TrackingUnit herstellen (optional)
Mittelfristig wird der *merchant* gewillt sein, die einzelnen trackingUnits in einer, seiner Organisation entsprechender Filialstruktur
zu platzieren. Dazu gibt es zwei Wege:
* **Über die API** - Verfügt Ihre Software über die korrekten Adressdaten zum eigenen Standort, sollte Ihre Software diese Daten
an Qnips melden, sodass Qnips ggf. automatisch eine Filial-Einheit für den Merchant anlegen und die trackingUnit dort einordnen kann.
Dazu bitte einen *[POST trackingUnit](#reference/trackingunits/details-hochladen/post-trackingunits)*-Call ausführen
* **Über das Qnips-Portal** - in diesem Fall werden neu angelegte trackingUnits mit dem Flag notCategorized angelegt und der
Merchant aufgefordert, die trackingUnit manuell über das Qnips-Portal in eine Filiale einzuordnen
Wird die Kasse irgendwann an einen anderen Standort verbracht, sollte diese Standortänderung entweder über einen weiteren
*[POST trackingUnit](#reference/trackingunits/details-hochladen/post-trackingunits)*-Call
(sofern die Adressdaten in der Kasse aktualisiert werden) oder durch den manuellen
Eingriff des merchants im Qnips Dasboard bewerkstelligt werden. Bis zur Meldung dieses Umzugs würden die von dieser Kasse im
Qnips-System erzeugten Daten noch unter der alten Filiale zusammenlaufen.
# Einkaufsbewertung
Unter Einkaufsbewertung verstehen wir:
* artikelgenaues Produktfeedback
* Bediener-Bewertung
* Beantwortung beliebiger, vom *merchant* hinterlegter Fragen im Kauf-Kontext.
Die Bewertung erfolgt über einen Fragebogen, der aus einem *basket*-Datensatz generiert und dem *consumer* angezeigt wird, sobald er sich als Käufer des jeweiligen baskets legitimiert.
1. Identifiziert sich der Konsument direkt am POS (z.B. indem das POS einen QrCode vom Bildschirm seines Smartphones abliest),
fügen Sie dem Upload des *basket*-Datensatzes
(siehe *[POST baskets/{basketId}](#reference/baskets/basket-hochladen/post-baskets%2F%7Bbasketid%7D%3Fconsumeridenttoken%3D%7Btoken1%7D%26giftcardid%3D%7Btoken2%7D)*)
den optionalen **consumerIdentToken**-Parameter hinzu.
Dies wird eine Push-Nachricht ans Smartphone des Konsumenten generieren,mit der Bitte, den Fragebogen auszufüllen.
2. Gibt es keine direkte Konsumenten-Identifikation am POS, so kann der Konsument den vom POS-System auf der Rechnung gedruckten
QRCode abscannen und bekommt den Fragebogen eben nach dem Scan serviert.
Drucken Sie daher auf **jedem** Rechnungsbeleg einen QRCode mit folgendem Inhalt auf, nachdem Sie
*[POST baskets/{basketId}](#reference/baskets/basket-hochladen/post-baskets%2F%7Bbasketid%7D%3Fconsumeridenttoken%3D%7Btoken1%7D%26giftcardid%3D%7Btoken2%7D)* ausgeführt haben:
**“http:\\app.qnips.com\t1\\{trackingUnitId}\\{basketId}”**
# Rewards
Qnips bietet fogende Rewardtypen an:
+ Umsatzbasierte Coupons (z.B. ab 20€ Umsatz 10% Rabatt)
+ Produktbasierte Coupons (z.B. 20% auf alle Herrenstiefel)
+ Coupons auf Produktkombinationen (z.B. Schnürsenkel zum Herrenschuh zum halben Preis)
+ Mengencoupons (z.B. 3 zum Preis von 2)
+ Umsatz- und/oder produktbasierte Punkte-Sammelsysteme mit flexibel gestaltbaren Rabatten
Die auf einen *basket* anrechenbaren Rewards werden immer sofort nach dem Upload des basket-Datensatzes in Echtzeit errechnet und an Ihre
Software zurückgeliefert. Der vollständige Prozess der Reward-Anrechnung sieht wie folgt aus:
1. Erfassen Sie den Warenkorb
2. Führen Sie ggf. eine Konsumenten-Identifizierung durch ( *token1* )
Je nach Wunsch eines Händlers kann die Identifizierung eines Konsumenten individuell geartet sein. So ist z.B. das Einlesen
eines *consumerIdentTokens* von einer Kundenkarte, vom Display des Smartphones des Konsumenten oder z.B. über einen NFC-Reader
möglich. Allen ist jedoch gemein, dass am Ende am POS ein sogenannter *consumerIdentToken* vorliegt, der im Qnips-System eindeutig
einem Konsumenten-Profil zugeordnet ist
3. Erfassen Sie ggf. vorgezeigte Geschenk-/Guthabenkarte ( *token2* )
4. Rufen Sie [POST baskets/{basketId}?consumerIdentToken={token1}&giftCardId={token2}](#reference/baskets/basket-hochladen/post-baskets%2F%7Bbasketid%7D%3Fconsumeridenttoken%3D%7Btoken1%7D%26giftcardid%3D%7Btoken2%7D) auf
Der Response auf diesen POST könnte wie folgt aussehen:
{
"Rewards":[
{
"RewardType":1,
"ProductId":"123",
"NetRewardValue":10.0,
"ApplicableTaxInPercent":19.0
}],
"Balances":[
{
"TokenId":"member123",
"Balance":50.0,
"CurrencyISO":"EUR"
},
{
"TokenId":"giftCardABC",
"Balance":25.0,
"CurrencyISO":"EUR"
}]
}
5. Verarbeiten Sie `Rewards` im Response
Sie können die Rewards direkt in die Rechnung einarbeiten und den Rechnungsbetrag entsprechend reduzieren. Bitte beachten Sie, dass
die **nicht** auf ein Einzelprodukt bezogenen Rewards in Ihrer Software ggf. auf die einzelnen Rechnungspositionen umgelegt werden
müssen, um die korrekte Mehrwertsteuer auf den Reward-Betrag ermitteln zu können. Solche Rewards erkennen Sie am `RewardType`=2.
Werden die Rewards nicht von Ihrer Software direkt verrechnet, kann die Auszahlung der Rewards über das Qnips-Cashback-System erfolgen - die
Rewards werden vom Qnips-System dem Konto des Händlers belastet und dem vituellen consumer-Konto gutgeschrieben, von welchem der
Konsument die Auszahlung seiner gesammelten Rewards jederzeit über die Qnips-App oder den consumer-Webclient beantragen kann.
Die Auszahlung als Cashback kommt immer dann zum Tragen, wenn der Konsument sich nicht während des Kaufs am POS identifizieren kann
und sich erst im Nachgang über den Scan des QrCodes auf der Rechnung als Käufer des baskets und somit auch als legitimer Empfänger der
im basket eventuell enthaltener Rewards ausweist.
6. Verarbeiten Sie `Balances` im Response
Wurde beim Einreichen des baskets (Schritt 4) ein `consumerIdentToken` und/oder eine Geschenkkarten-ID angegeben, wird der Response ggf.
die Information über mögliche Guthaben enthalten. Diese Guthaben können nach Ihrem Ermessen bzw. nach dem Wunsch des Händlers
mit dem Rechnungsbetrag verrechnet werden. Fangen Sie bei der Anrechnung bitte immer mit dem Guthaben der Geschenkkarte an.
Wurden die im Response ausgewiesenen Guthaben ganz oder anteilig mit dem Rechnungsbetrag verrechnet, müssen diese in unserem System
um den entsprechenden Betrag reduziert werden. Führen Sie dazu
[POST token/{id}/withdrawBalance}](#reference/tokens/guthaben-abheben/post-tokens%2F%7Bid%7D%2Fwithdrawbalance%3Fbalancetowithdraw%3D%7Bbalancetowithdraw%7D) aus
7. basket als abgeschlossen markieren
Solange ein basket nicht abgeschlossen (`granted`) ist, kann er beliebig oft neu eingereicht werden. Mit jeder Neueinreichung würden
die Rewards neu berechnet werden und die alten ersetzen. Somit lässt sich eine
nachträgliche Stornierung oder Nacherfassung von Positionen in einem basket abbilden. Ist jedoch aus der Sicht des Konsumenten ein
finaler Stand erreicht und der Rechnungsbetrag beglichen, muss der basket in unserem System als `granted` markiert werden.
Führen Sie dazu *[POST baskets/{basketId}/grant?redeemedInPos={boolean}](#reference/baskets/rewards-als-granted-markieren)* aus und
geben Sie im `redeemedInPos`-Parameter an, ob der POS-Client auf Direktverrechnung der Qnips-Rewards eingestellt ist oder nicht (siehe Schritt 5)
*ACHTUNG: Mit der Implementierung des oben beschriebenen Prozesses lassen sich alle umsatzbasierten Rewards nutzen. Damit ein Händler auch produktbasierte Rewards erstellen kann, muss unser System zumindest die Produkte kennen, für welche der Händler Rewards definieren möchte. Dazu muss Ihre Software zusätzlich das Kapitel [Sortimentspflege](#introduction/sortimentspflege) implementieren.*
# Sortimentspflege
Unter Sortimentspflege verstehen wir den initialen Upload sowie das Updaten der Produkt-/Artikel-Daten in unserem System. Die Sortimentspflege ist eine Voraussetzung für folgende Qnips-Features:
+ produktbezogene Rewards
Für produktbezogene Rewards ist es ausreichend, nur solche Produkte (bzw. Produktgruppen) an das Qnips-System zu
übermitteln, für die der merchant einen Reward einrichten will. Hierbei reicht es, wenn die Artikel in Ihrer
Minimalform (nur PLU und Name, sowie ggf. eine Warengruppenzuordnung) eingereicht werden.
+ Menükarten-Anzeige in der App inkl. Allergen-/Nährwert-/Zusatzstoffe-Angaben
Speziell für Gastronomie und Gemeinschaftsverpflegung im Speziellen bieten wir die Funktion eines umfangreichen,
LMIV-konformen Speiseplans mit eigenem Allergen-/Zusatzstoff-Management auf Artikelebene. Verfügt Ihr System über
solche Angaben, können sie ebenfalls an unserem System hochgeladen werden, sodass das Allergen-/Zusatzstoff-Management
weiterhin in Ihrer Software verbleibt und lediglich die Zusammenstellung des Speiseplans über uns erfolgen kann
*HINWEIS: Implementieren Sie das Feature bitte so, dass der merchant letztendlich entscheiden kann, in welchem Umfang ein Sortiment an Qnips hochgeladen wird, indem Sie in Ihrem System z.B. eine Möglichkeit schaffen, die an Qnips zu übertragenen Artikel als solche zu markieren.*
## Sortimente
Artikeldaten sind im Qnips-System in so genannten `sortimenten` organisiert. Ein sortiment kann von mehreren `trackingUnits`
an einem oder auch an unterschiedlichen Standorten gemeinsam verwendet werden. Das einzige Unterscheidungsmerkmal,
ob ein Artikel von mehreren trackingUnits im selben Sortiment gepflegt werden kann, ist die Eindeutigkeit seiner
PLU → ist unter der selben PLU auf zwei trackingUnits ein unterschiedlicher Artikelname erfasst, so müssen diese
Artikel in unterschiedliche Sortimente geladen werden.
Rufen Sie dazu [GET sortiments?thirdPartySortimentIdentifier={string1}&name={string2}](#reference/sortiments/sortimentid-besorgen) auf.
## Upload
Die Artikeldaten lassen sich sowohl einzeln als auch per BulkUpload hochladen bzw. updaten:
+ [POST / PUT / DELETE sortiments/{qnipsSortimentId}/group](#reference/sortiments/warengruppen-bearbeiten)
+ [POST / PUT / DELETE sortiments/{qnipsSortimentId}/article](#reference/sortiments/artikel-bearbeiten)
+ [POST sortiments/{qnipsSortimentId}/bulkUpload?changedArticlesOnly={boolean}](#reference/sortiments/bulkupload)
# Kundenkarten
Kundenkarten sind neben QrCode-Scans eine weitere Möglichkeit, einen `basket` mit einem bestimmten Konsumenten-Profil zu verknüpfen.
Das Verfahren dabei ist recht einfach: am POS wird ein beliebig gearteter Identifier von irgendeinem vom Konsumenten am POS vorgezeigten
Identifier-Träger ausgelesen und als `consumerIdentToken` zusammen mit einem `basket` an unserem System eingeschickt.
Daher ist es für uns unwichtig, ob dieser Token
+ auf einem Magnetstreifen oder NFC-Chip einer Plastikkarte
+ im Barcode oder QrCode einer Papierkarte
+ in einem RFID-Transponder
+ als virueller Token auf dem Smartphone des Konsumenten
+ oder sonstiges
gespeichert ist. Genauso unwichtig ist es, von wem ein solcher Token generiert worden ist, solange er unveränderbar und
eindeutig genug ist, um seinen Halter von anderen Konsumenten unterscheiden zu können.
## Kundenkarte registrieren
Eine Kundenkarte lässt sich daher einfach realisieren, indem der in der Karte gespeicherte Karten-Identifier als sogenannter `token`
in unserem System bekannt gemacht wird. Lesen Sie dazu den Identifier von einer Karte aus, die Sie an den Konsumenten als Kundenkarte
aushändigen wollen und führen Sie [POST tokens/{id}](#reference/tokens/token-registrieren/post-tokens%2F%7Bid%7D%3Ftokentype%3D%7Btokentype%7D) unter Angabe dieses Identifiert als `{id}` aus.
## Kundenkarte sperren
Sperrung von Kundenkarten kann vom Merchant entweder direkt im Webportal vorgenommen werden, oder, wenn Ihre Software die führende
Verwaltungsstelle für Kundenkarten darstellt, über einen API-Call uns mitgeteilt werden. Führen Sie dazu eine der beiden Aktionen aus:
+ [POST tokens/{id}/lock](#reference/tokens/token-sperren/post-tokens%2F%7Bid%7D%2Flock)
Diese Aktion macht eine Karte komplett unbrauchbar.
+ bzw. [POST tokens/{id}/dispose](#reference/tokens/token-freigeben/post-tokens%2F%7Bid%7D%2Fdispose)
Entbindet die Karte lediglich von einem Konsumenten-Profil, die Karte selbst steht jedoch für eine neue Registrierung und eine Verwendung durch einen anderen Konsumenten weiterhin zur Verfügung
## Karte mit Guthaben aufladen
Kundenkarten können mit einem Guthaben aufgeladen werden. Die Aufladung kann einerseits vom Konsumenten über unser Konsumenten-Portal
aufgeladen werden (z.B. mittels einer Überweisung oder via PayPal). Andererseits wäre es sinnvoll, eine Auflademöglichkeit auch am POS
zu schaffen. Stellen Sie dazu einem Konsumenten eine Rechnung aus, ziehen Sie das Geld ein und buchen Sie das Guthaben auf seine Kundenkarte,
indem Sie den `token` seiner Kundenkarte erfassen und den folgenen Call durchführen:
[POST tokens/{id}/addBalance?balanceToAdd={balanceToAdd}](#reference/tokens/guthaben-aufladen/post-tokens%2F%7Bid%7D%2Faddbalance%3Fbalancetoadd%3D%7Bbalancetoadd%7D)
## Guthaben abheben
Liegt auf einer Kundenkarte ein Guthaben und wird von Ihrem System ein `basket` mit dem `token` dieser Kundenkarte eingeschickt,
so wird der Response zum [POST basket/{basketId}?consumerIdentToken={token1}](#reference/baskets/basket-hochladen/post-baskets%2F%7Bbasketid%7D%3Fconsumeridenttoken%3D%7Btoken1%7D%26giftcardid%3D%7Btoken2%7D)
die Höhe dieses Guthabens enthalten.
Wird der Anteil dieses Guthabens mit dem Rechnungsbetrag verrechnet, so rufen Sie
[POST tokens/{id}/withdrawBalance?balanceToWithdraw={balanceToWithdraw}](#reference/tokens/guthaben-abheben/post-tokens%2F%7Bid%7D%2Fwithdrawbalance%3Fbalancetowithdraw%3D%7Bbalancetowithdraw%7D) auf.
# Geschenkkarten
Eine `Geschenkkarte` wird in unserem System komplett wie eine `Kundenkarte` behandelt, mit dem einzigen Unterschied, dass der Halter
einer Geschenkkarte im Unterschied zum Halter einer Kundenkarte keinen öffentlichen Zugang über das Konsumenten-Portal zu den
Aktivitäten (Auflade- und Entlade-Vorgänge, mit der Karte gekaufte und ggf. bezahlte `baskets` etc.) erhält.
*Implementierungstechnisch ist eine `Geschenkkarte` jedoch komplett zur `Kundenkarte` identisch*
#Group merchants
Die im Qnips-System registrierten Händler werden `merchants`genannt. Ein Merchant wird mit seinem `qnipsUserName` identifiziert, mit welchem er sich auch im Webportal von Qnips (unter http://my.qnips.com)
anmelden kann. Jeder Merchant kann mehrere Handelsmarken mit jeweils mehreren Standorten besitzen. Daher braucht unser System für die Registrierung eines Zugangs für Ihr System immer mindestens zwei Angaben:
* **qnipsUserName**
* **brandId**
Nach Eingabe eines `qnipsUserName` durch den Bediener, sollte Ihr System mit *[GET merchants/{qnipsUserName}/brands](#reference/merchants/brands-abrufen/get-merchants/{qnipsUserName}/brands)* die `brands` abrufen und dem Bediener zur
Auswahl anzeigen.
Wird im Response nur ein `brand` zurückgeliefert wird, so kann die Registrierung über einen *[GET trackingUnits](#reference/trackingunits/registrieren/get-trackingunits)*-Call direkt erfolgen.
## Brands abrufen [/merchants/{qnipsUserName}/brands]
### GET merchants/{qnipsUserName}/brands [GET]
| Rückgabe | Beschreibung |
| --- | --- |
|`brandId`|Id des Brands.|
|`brandName`|Name des Brands.|
+ Parameters
+ qnipsUserName (string, `'hans.möller@firma.de' -> 'hans.m%C3%B6ller@firma.de'`) ... Lassen Sie den Merchant seinen `qnipsUserName` eintragen und fügen Sie diesen hier ein. Der Wert sollte URL-konform escaped werden, da er Umlaute enthalten kann.|
+ Request
+ Headers
Accept: application/json
DevKey: {Ihr Key}
+ Response 200
[
{
"brandId": 1,
"brandName": "Caesar's"
},
{
"brandId": 2,
"brandName": "Apostels"
},
]
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
+ Response 401
// HTTP-Unauthorized: DevKey nicht angegeben oder nicht vorhanden
+ Response 404
// HTTP-NotFound: qnipsUserName unbekannt oder hat keine brands
#Group trackingUnits
## Registrieren [/trackingUnits?qnipsUserName={string}&brandId={brandId}&instanceName={string}&city={string}&street={string}&postalIndex={string}]
### GET trackingUnits [GET]
Jeder Call auf diese Resource wird immer einen neuen, sich vom vorherigen Call unterscheidenden Identifier, die sog. `trackingUnitId` sowie ein `checksumSecret` im Response liefern.
| Rückgabe | Beschreibung |
| --- | --- |
|`trackingUnitId`|Diese Id werden Sie bei jedem weiteren Call im `TrackingUnitId-Request-Header` setzen müssen, ohne welchen jeder Call von unserem Backend abgewiesen würde.|
|`checksumSecret`|Diesen `Secret` werden Sie zur Bildung einer Prüfziffer benötigen, die bei einigen Calls unserer API als Sicherheitskriterium mit übermittelt werden muss.|
Rufen Sie diese Resource daher in jedem zu registrierenden Terminal nur einmal auf, persistieren Sie die beiden Werte aus dem Response und sorgen Sie dafür, dass der `checksumSecret` geheim bleibt.
+ Parameters
+ qnipsUserName (string, `'hans.möller@firma.de' -> 'hans.m%C3%B6ller@firma.de'`) ... Lassen Sie den Merchant seinen Qnips-Username eintragen und geben Sie diesen hier an. Der Wert sollte URL-konform escaped werden, da er Umlaute enthalten kann.|
+ instanceName (string, `'Filiale 5 - Kasse im Gang 1' -> 'Filiale%205%20-%20Kasse%20im%20Gang%201'`) ... Lassen Sie den Merchant im Zuge der Qnips-Aktivierung einen Namen für die zu aktivierende Instanz eintragen und geben Sie diese hier an. Der hier eingegebene Name wird im Qnips-Webportal für den Merchant sichtbar sein und hilft dem Merchant, diese Instanz ggf. korrekt einzuordnen. Der Wert sollte URL-konform escaped werden, da er z.B. Umlaute und Leerzeichen enthalten kann.|
+ city (optional, string, `'Köln' -> 'K%C3%B6ln'`) ... Oprionale Angabe zum Filialstandort, in welchem diese trackingUnit betrieben wird. Der Wert sollte URL-konform escaped werden, da er z.B. Umlaute und Leerzeichen enthalten kann.|
+ street (optional, string, `'Möbiusweg 1' -> 'M%C3%B6biusweg%201'`) ... Oprionale Angabe zum Filialstandort, in welchem diese trackingUnit betrieben wird. Der Wert sollte URL-konform escaped werden, da er z.B. Umlaute und Leerzeichen enthalten kann.|
+ postalIndex (optional, string, `'50667'`) ... Oprionale Angabe zum Filialstandort, in welchem diese trackingUnit betrieben wird.|
+ Request
+ Headers
Accept: application/json
DevKey: {Ihr Key}
+ Response 200
{
"trackingUnitId" = "1234567890",
"checksumSecret" = "def567",
}
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
+ Response 401
// HTTP-Unauthorized: DevKey oder trackingUnitId nicht angegeben oder nicht vorhanden
+ Response 400
{
"ErrorId":123,
"ErrorText":"Details zum Fehler"
}
// hier alle möglichen ErrorCodes inkl. Texte für diese Resource
// 10001: unbekannter qnipsUserName
// 10002: kein Instanz-Name angegeben
## Details hochladen [/trackingUnits]
### POST trackingUnits [POST]
Mit diesem Call können Sie die Standortinformationen der trackingUnit hochladen, sofern in Ihrem System verfügbar. Dies wird dazu führen,
dass mit den übermittelten Adressdaten ggf. eine neue Filial-Einheit im Qnips-System angelegt und die trackingUnit dieser automatisch zugeordnet wird.
Bei jedem Call werden die Werte in city, street und postalIndex mit den zuvor für diese trackingUnit abgespeicherten Werten verglichen.
Unterscheiden sich diese, wird die trackingUnit automatisch in die neue Filiale verknüpft.
#### Parameter des Body-Objekts
| Name | Beschreibung |
| --- | --- |
|`instanceName`|**string : optional** - Lesbarer Name, unter welchem diese Unit im Qnips Merchant Portal für den merchant sichtbar sein wird, z.B. „Kasse im Gang 5“|
|`city`|**string : optional** - Angabe zum Filialstandort, in welchem diese trackingUnit betrieben wird|
|`street`|**string : optional** - Angabe zum Filialstandort, in welchem diese trackingUnit betrieben wird|
|`postalIndex`|**string : optional** - Angabe zum Filialstandort, in welchem diese trackingUnit betrieben wird|
+ Request
+ Headers
Content-Type: application/json
DevKey: {Ihr Key}
TrackingUnitId: {trackingUnitId}
+ Body
{
"instanceName":"Filiale 5 - Kasse Gang 1",
"city":"Hannover",
"street":"Weidendamm 8",
"postalIndex":"30167",
}
+ Response 200
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
+ Response 401
// HTTP-Unauthorized: DevKey oder trackingUnitId nicht angegeben oder nicht vorhanden
+ Response 400
{
"ErrorId":123,
"ErrorText":"Details zum Fehler"
}
// hier alle möglichen ErrorCodes inkl. Texte für diese Resource
// 1000: Body enthält syntaktische Fehler und kann nicht deserialisiert werden
#Group baskets
## Basket hochladen [/baskets/{basketId}?consumerIdentToken={token1}&giftCardId={token2}]
### POST baskets/{basketId}?consumerIdentToken={token1}&giftCardId={token2} [POST]
Ein basket ist der Inhalt einer Rechnung und stellt die Grundlage für die meisten Qnips-Funktionen dar.
Das Ergebnis dieses Calls beinhaltet immer die möglichen `Rewards`, für die im basket enthaltenen Produkte.
Diese errechneten `Rewards` stellen ein vorläufiges Ergebnis fest und müssen von Ihrer Software als `granted` markiert werden,
sobald der Rechnungsbetrag voll beglichen ist, damit die Rewards wirksam werden und dem consumer als eingelöst gemeldet
werden können (siehe *[POST baskets/{basketId}/grant](#reference/baskets/rewards-als-granted-markieren/post-baskets%2F%7Bbasketid%7D%2Fgrant%3Fredeemedinpos%3D%7Bredeemedinpos%7D)*)
Wurden beim Call ein *consumerIdentToken* oder eine *giftCardId* angegeben, so kann der Response auch die Information über
potentiell vorhandene Guthaben entweder auf dem Konsumenten-Profil oder auf der Geschenk-Karte enthalten.
Solange ein basket nicht `granted` ist, kann er über den erneuten Call auf diese Resource beliebig oft geupdated werden,
z.B. weil kurzerhand noch eine Position nachgebucht oder gestrichen wurde (ein häufiger Fall in der Gastronomie).
Jeder neue Call wird dabei eine erneute Berechnung der Rewards anstoßen und ausliefern.
#### Parameter im Request-Body
Da die Bedeutung der meisten Properties über den Namen klar sein sollte, hier nur einige wenige Erklärungen zu den erklärungsbedürftigen Properties.
| Name | Beschreibung |
| --- | --- |
|`Timestamp`|**DateTime : required** - hier sollte der Zeitpunkt der Rechnungsstellung im *[ISO8601-Format](http://de.wikipedia.org/wiki/ISO_8601)* inkl. Zeitzone angegeben werden. Beispiel: 2015-04-30T08:45:15+02:00 für 08:45:15 Uhr am 30. April 2015 in Berlin (MESZ – Sommerzeit)|
|`HasDiscounts`|**bool : required** - wird hier true angegeben, findet für diesen basket keine Reward-Berechnung im Qnips-System statt|
|`CurrencyISO`|**string : optional** - Geben Sie die Währung, in der abgerechnet wird, als 3-stellige Abkürzung nach *[ISO 4217](http://de.wikipedia.org/wiki/ISO_4217)*|
|`WaiterName`|**string : optional** - hier sollte der Name des Bedieners/Kassierers stehen, der den Kunden maßgeblich bedient/beraten hat|
|`BillPdf`|**Byte-Array : optional** - Um das Features des Digitalen Bons auch den Konsumenten ohne Smartphone anbieten zu können, kann Ihre Software die Kopie der Rechnung als eine PDF-Datei an uns schicken, damit wir diese einerseits im Qnips Consumer Portal anzeigen, aber auch direkt per Email an den Konsumenten verschicken können. Schicken Sie hier dazu den Inhalt der PDF-Datei als base64-kodierter Byte-Array|
|`RegularGrossPrice`|**double : optional** - hier sollte der normale Verkaufspreis für den Artikel angegeben werden|
|`CurrentGrossPrice`|**double : optional** - hier sollte der Preis stehen, unter welchem dieser Artikel in dieser Rechnung verkauft wird, z.B. wenn irgendwelche Discounts (Aktionen, Mitarbeiterrabatte etc.) auf diesen Artikel angewendet wurden.|
|`ProductId`|**string : optional** - geben Sie hier die PLU des Produkts, unter welcher das Produkt an unser System eingereicht wurde, damit wir dieses korrekt für die Berechnung der produktbasierten Rewards erkennen können. Haben Sie in Ihrer Software keine Unterstützung für produktbasierte Rewards implementiert, können Sie dieses Feld auslassen|
|`OrderTime`|**DateTime : optional** - in der Gastronomie ist häufig anzutreffen, dass eine Rechnung längere Zeit offen steht und Positionen nach und nach gebucht werden. Ist dies bei Ihnen auch der Fall, geben Sie hier den genauen Buchungszeitpunkt der jeweiligen Position im *[ISO8601-Format](http://de.wikipedia.org/wiki/ISO_8601)* (inkl. Zeitzone) an. Dies wird uns erlauben, sog. “Happy Hour”-Rewards auf eine Position genau berechnen zu können. Beispiel: 2015-04-30T08:45:15+02:00 für 08:45:15 Uhr am 30. April 2015 in Berlin (MESZ – Sommerzeit)|
|`ProductProps`|**dictionary[string, string] : optional** - Haben Ihre Produkte besondere Eigenschaften, die auf dem Digitalen Kassenbon strukturiert angezeigt werden sollen, so ist diese Liste der Key-Value-Pairs genau der richtige Ort für diese Eigenschaften|
#### Response
Der Response-Body enthält eine Liste der auf den eingereichten basket anwendbaren Rewards sowie ggf. Guthaben auf einer Kunden- bzw. Geschenkkarte, sofern deren IDs als URL-Parameter beim Call angegeben wurden. Die Rewards-Liste wird leer sein,
wenn kein Reward anwendbar ist. Anderenfalls ist es eine Liste mit Objekten, die jeweils einen Reward pro einzelnen Artikel darstellen oder sich auf den Gesamt-Rechnungsbetrag beziehen.
Jedes Objekt hat dabei folgende Properties:
| Name | Beschreibung |
| --- | --- |
|`RewardType`|**int**: 1 = Reward auf Produkt. 2 = Reward auf Gesamt-Rechnungsbetrag. Bei 1 wird die `ProductId` mit der PLU des Produktes belegt, für welchen dieser Reward ermittelt wurde. Bei 2 bleibt das Feld `ProductId` leer.|
|`ProductId`|**string**: die PLU des im basket-Datensatz übermittelten Artikels, auf welchen ein Reward ermittelt werden konnte.|
|`NetRewardValue`|**decimal**: das ist der errechnete Netto-Wert (ohne MwSt) des Rewards. Bitte beachten Sie, dass dieser Betrag bei `RewardType`=2 in Ihrer Software auf die einzelnen Positionen umgelegt werden sollte, wenn in Ihrer Software eine Direktverrechnung der Rewards mit dem Rechnungsbetrag erfolgt. |
|`ApplicableTaxInPercent`|**decimal**: dies ist der Mehrwertsteuersatz als Dezimalzahl (z.B. 19.0) für den Reward. Er bleibt leer, wenn `RewardType`=2, da der Reward sich auf den Gesamt-Rechnungsbetrag mit u.U. unterschiedlichen MwSt-Anteilen bezieht. Bei `RewardType`=1 wird er hingegen aus dem Feld `VatInPercent` der Rechnungsposition des ursprünglichen basket-Datensatzes abgeleitet, für welche der Reward ermittelt wurde.|
Und hier die Erklärung der Properties eines Balance-Objekts:
| Name | Beschreibung |
| --- | --- |
|`TokenId`|**string**: das ist die `giftCardId` bzw. der `consumerIdentToken` des Kunden-Profils, wie im Request angegeben|
|`Balance`|**decimal**: das ist die Höhe des Guthabens auf der Karte|
|`Currency`|**string**: die Währung, in der das Guthaben vorliegt, als 3-stellige Abkürzung nach *[ISO 4217](http://de.wikipedia.org/wiki/ISO_4217)*|
+ Parameters
+ basketId (string, `'ab12345'`) ... Ein frei von Ihrem Client erzeugbarer String, welcher den basket eindeutig identifiziert. Sie können hier z.B. die Rechnungsnummer als `basketId` verwenden.
+ token1 (optional, string, `'member123'`) ... Hat sich der Konsument bereits am POS z.B. durch Vorzeigen einer Kundenkarte identifiziert, in welcher der mit seinem Konsumenten-Profil verlinkte `token` gespeichert ist, sollte dieser `token` hier angegeben werden.
+ token2 (optional, string, `'giftCardABC'`) ... Hatte der Konsument beim Kauf eine Geschenkkarte vorgezeigt und wurde diese von Ihrem System erfasst, sollte hier die in der Karte gespeicherte ID angegeben werden
+ Request
+ Headers
Content-Type: application/json
DevKey: {Ihr Key}
TrackingUnitId: {trackingUnitId}
+ Body
{
"BillNumber":"1234",
"Timestamp":"2015-04-21T08:15:45.000+02:00",
"TotalValue":159.90,
"HasDiscounts":false,
"TableId":"123",
"WaiterName":"Max Mustermann",
"CurrencyISO":"EUR",
"Positions":[
{
"ProductId":"123",
"ProductName":"Adidas Sneaker 123",
"Amount":2,
"HasDiscounts":false,
"CurrentGrossPrice":79.95,
"RegularGrossPrice":79.95,
"VatInPercent":19.0,
"OrderTime":"2015-04-21T08:15:45.000+02:00",
"ImageUrl":"http://abc.de/xyz",
"ProductProps":{
"Größe":"43",
"Farbe":"black"
}
}
],
"BillPdf":"98761238467129803470987809123489798172435980728347578091873645786..."
}
+ Response 200
+ Headers
Content-Type: application/json
+ Body
{
"Rewards":[
{
"RewardType":1,
"ProductId":"123",
"NetRewardValue":10.50,
"ApplicableTaxInPercent":19.0
},
{
"RewardType":2,
"ProductId":null,
"NetRewardValue":10.50,
"ApplicableTaxInPercent":null
}],
"Balances":[
{
"TokenId":"member123",
"Balance":50.0,
"CurrencyISO":"EUR"
},
{
"TokenId":"giftCardABC",
"Balance":25.0,
"CurrencyISO":"EUR"
}]
}
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
+ Response 401
// HTTP-Unauthorized: DevKey oder trackingUnitId nicht angegeben oder nicht vorhanden
+ Response 403
// HTTP-Forbidden: trackingUnitId ist noch nicht vom Merchant aktiviert
+ Response 400
{
"ErrorId":123,
"ErrorText":"Details zum Fehler"
}
// hier alle möglichen ErrorCodes inkl. Texte für diese Resource
// 1000: Body enthält syntaktische Fehler und kann nicht deserialisiert werden
// 11004: consumerIdentToken nicht gefunden. Wiederholen Sie ggf. ohne diesen Token
// 11005: consumerIdentToken gesperrt. Wiederholen Sie ggf. ohne diesen Token
// 11006: consumerIdentToken abgelaufen. Wiederholen Sie ggf. ohne diesen Token
// 11007: giftCardId nicht gefunden. Wiederholen Sie ggf. ohne diesen Token
// 11008: giftCardId gesperrt. Wiederholen Sie ggf. ohne diesen Token
// 11009: giftCardId abgelaufen. Wiederholen Sie ggf. ohne diesen Token
// 11010: dieser basket ist `granted` und somit nicht mehr veränderbar
## Rewards als `granted` markieren [/baskets/{basketId}/grant?redeemedInPos={redeemedInPos}]
### POST baskets/{basketId}/grant?redeemedInPos={redeemedInPos} [POST]
Erst durch das Markieren eines baskets als `granted` betrachtet das Qnips-System die ermittelten Rewards als legitim und schreibt diese
dem Konsumenten gut. Es werden dabei genau die Rewards als `granted` markiert, die bei dem letzten
*[POST baskets/{basketId}](#reference/baskets/basket-hochladen/post-baskets%2F%7Bbasketid%7D%3Fconsumeridenttoken%3D%7Btoken1%7D%26giftcardid%3D%7Btoken2%7D)*-Call für den basket mit der angegebenen
basketId ermittelt und zurückgeliefert wurden.
Geben Sie für den `redeemedInPos`-Parameter den Wert `true` wenn Ihr System bei dem aktuellen Händler die Qnips-Rabatte direkt verrechnet.
+ Parameters
+ basketId (string, `1234567890`) ... Geben Sie hier die Id des baskets, den Sie als abgeschlossen markieren wollen
+ redeemedInPos (bool, `true` ) ... Verwenden Sie **true** wenn Ihr System bei dem aktuellen Händler die Qnips-Rabatte direkt verrechnet.
+ Request
+ Headers
DevKey: {Ihr Key}
TrackingUnitId: {trackingUnitId}
+ Response 200
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
+ Response 401
// HTTP-Unauthorized: DevKey oder trackingUnitId nicht angegeben oder nicht vorhanden
+ Response 403
// HTTP-Forbidden: trackingUnitId ist noch nicht vom Merchant aktiviert
+ Response 400
{
"ErrorId":12000,
"ErrorText":"Details zum Fehler"
}
// hier alle möglichen ErrorCodes inkl. Texte für diese Resource
// 11001: basketId unbekannt
#Group sortiments
## sortimentId besorgen [/sortiments?thirdPartySortimentIdentifier={string1}&name={string2}]
### GET sortiments?thirdPartySortimentIdentifier={string1}&name={string2} [GET]
Bevor ein Artikel im Qnips-System hochgeladen bzw. upgedated werden kann, muss die trackingUnit sich an einem Sortiment anmelden.
Dies geschieht mit diesem Call. Im Response erhalten Sie eine sogenannte `qnipsSortimentId`, die künftig bei jeder Operation auf dem
Sortiment anzugeben ist. Existiert noch kein Sortiment mit den angegebenen Parametern, wird eins angelegt und dessen ID
zurückgeliefert.
Speichern Sie die Rückgabe.
{
"qnipsSortimentId":"sortiment123"
}
Wird die Kasse in Ihrem System mit einem anderen Sortiment verknüpft, rufen Sie diese Resource erneut auf und speichern Sie die Rückgabe erneut ab.
+ Parameters
+ string1 (string, `1234567890`) ... hier ist der unique Identifier des Sortiments anzugeben, unter welchem er in Ihrem eigenen System geführt wird
+ string2 (optional, string, `'Sortiment Lounge-Bar' -> 'Sortiment%20Lounge-Bar'` ) ... ein für den merchant verständlicher Name, unter welchem er das Sortiment im Qnips-Dashboard sehen und ggf. bearbeiten können wird. Der Wert sollte URL-konform escaped werden.
+ Request
+ Headers
DevKey: {Ihr Key}
TrackingUnitId: {trackingUnitId}
+ Response 200
{
"qnipsSortimentId":"sortiment123"
}
+ Response 403
// HTTP-Forbidden: trackingUnitId ist noch nicht vom Merchant aktiviert
+ Response 401
// HTTP-Unauthorized: DevKey oder trackingUnitId nicht angegeben oder nicht vorhanden
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
{
"ErrorMessage":"some explanation"
"StackTrace":"text"
}
## Warengruppen bearbeiten [/sortiments/{qnipsSortimentId}/group/{Id}]
### POST sortiments/{qnipsSortimentId}/group} [POST]
+ Parameters
+ qnipsSortimentId (string, `'sortiment123'`) ... das ist die `qnipsSortimentId`, die beim Call auf `GET sortiments?thirdPartySortimentIdentifier={string1}&name={string2}` zurückgeliefert wurde.
+ Request
+ Headers
DevKey: {Ihr Key}
TrackingUnitId: {trackingUnitId}
+ Body
{
"Id":”123”,
"UpGroupId":"234",
"Name":[
{ "lang":"de-DE", "val":"Getränke" },
{ "lang":"de-CH", "val":"Getränke" },
{ "lang":"it-CH", "val":"Bevande" },
{ "lang":"fr-UK", "val":"Boissons" }
]
}
+ Response 200
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
+ Response 403
// HTTP-Forbidden: trackingUnitId ist noch nicht vom Merchant aktiviert
+ Response 401
// HTTP-Unauthorized: DevKey oder trackingUnitId nicht angegeben oder nicht vorhanden
+ Response 400
{
"ErrorId":123,
"ErrorText":"Details zum Fehler"
}
// hier alle möglichen ErrorCodes inkl. Texte für diese Resource
// 12001: qnipsSortimentId unbekannt
// 12002: Id-Feld nicht gesetzt
// 12003: Keine Warengruppe unter der angegebenen UpGroupId gefunden
// 12004: Es gibt bereits eine Warengruppe unter der angegebenen Id
// 12005: Name wurde nicht angegeben, wird aber in mind. einer Sprache erwartet
### PUT sortiments/{qnipsSortimentId}/group} [PUT]
+ Parameters
+ qnipsSortimentId (string, `'sortiment123'`) ... das ist die `qnipsSortimentId`, die beim Call auf `GET sortiments?thirdPartySortimentIdentifier={string1}&name={string2}` zurückgeliefert wurde.
+ Request
+ Headers
DevKey: {Ihr Key}
TrackingUnitId: {trackingUnitId}
+ Body
{
"Id":”123”,
"UpGroupId":"234",
"Name":[
{ "lang":"de-DE", "val":"Getränke" },
{ "lang":"de-CH", "val":"Getränke" },
{ "lang":"it-CH", "val":"Bevande" },
{ "lang":"fr-UK", "val":"Boissons" }
]
}
+ Response 200
+ Response 500
// HTTP-InternalServerError: Ein unbekannten Problem bei der Verarbeitung aufgetreten
{
"ErrorMessage":"some explanation"
"StackTrace":"text"
}
+ Response 403
// HTTP-Forbidden: trackingUnitId ist noch nicht vom Merchant aktiviert
+ Response 401
// HTTP-Unauthorized: DevKey oder trackingUnitId nicht angegeben oder nicht vorhanden
+ Response 400
{
"ErrorId":123,
"ErrorText":"Details zum Fehler"
}
// hier alle möglichen ErrorCodes inkl. Texte für diese Resource
// 1000: Body enthält syntaktische Fehler und kann nicht deserialisiert werden
// 12001: qnipsSortimentId unbekannt
// 12002: Id-Feld nicht gesetzt
// 12003: Keine Warengruppe unter der angegebenen UpGroupId gefunden
// 12005: Name wurde nicht angegeben, wird aber in mind. einer Sprache erwartet
// 12006: Kein Item unter angegebener Id gefunden
// 12007: UpGroupId darf nicht geändert werden. Löschen Sie den item statt dessen und legen Sie ihn in der anderen Warengruppe neu an
### DELETE sortiments/{qnipsSortimentId}/group/{Id}} [DELETE]
Warengruppen sind wie folgt aufgebaut:
{
"Id":”123”,
"UpGroupId":"234",
"Name":[
{ "lang":"de-DE", "val":"Getränke" },
{ "lang":"de-CH", "val":"Getränke" },
{ "lang":"it-CH", "val":"Bevande" },
{ "lang":"fr-UK", "val":"Boissons" }
]
}
| Property | Beschreibung |
| --- | --- |
|`Id`|**string**: Das ist der eindeutige Identifier für diese Warengruppe. Er kann als `UpGroupId` von einer anderen Warengruppe referenziert werden, wodurch eine beliebig tief geschachtelte Warengruppen-Hierarchie abgebildet werden kann. |
|`UpGroupId`|**string**: Ist diese Warengruppe eine Gruppe auf oberster Ebene, ist diese Angabe nicht erforderlich. Sonst geben Sie hier den Identifier der Warengruppe, welcher diese Einheit untergeordnet werden soll.|
|`Name`|**translatable**: Hier kann der Name der Warengruppe in beliebig vielen Übersetzungen im Format, das weiter unten beschrieben wird, angegeben werden. Bitte geben Sie den Namen stets mindestens in einer Sprache an. |
#### Übersetzbare Properties (`translatable`)
Manche String-Properties von einigen Entitäten, wie z.B. der Name eines Artikels im Sortiment kann unser System in mehreren Übersetzungen entgegennehmen.
In dieser Dokumentation sind solche Properties als `translatable` markiert. Die Übergabe der Werte für solche Properties ist immer als eine Liste von
Translatable-Objekten zu erfolgen. Im `lang`-Property des Translatable-Objekts ist der Language-Tag nach [RFC 5646]() und die Übersetzung des Wertes
in der entsprechenden Sprache im `val`-Feld anzugeben.
JSON-Beispiel:
"Name":[
{ "lang":"de-DE", "val":"Getränke" },
{ "lang":"de-CH", "val":"Getränke" },
{ "lang":"it-CH", "val":"Bevande" },
{ "lang":"fr-UK", "val":"Boissons" }
]
XML-Beispiel:
de-DE
Getränke
de-CH
Getränke
it-CH
Bevande
fr-CH
Boissons