Documentation
Loyalty cards

Loyalty cards

This page describes an extension to Qerko API for loyalty cards. This allows the customer to add his loyalty card to Qerko app and enjoy benefits which are offered by the restaurant. The card can work across multiple restaurants.

Usage perspective

  1. I want to use my loyalty card when I pay by Qerko. So I decide to add my loyalty card into Qerko app. I pick the brand of my loyalty card from the list of supported cards. Qerko app asked me for some information about the card. So I fill in the required information and submit it.

  2. Qerko app presents me with the result of my request. It can be:

    1. The card is authorized and I can use it.

    2. The card is unauthorized for whatever reason so I need to resolve the problem with somebody.

    3. I have to perform some additional action described by a message. Eg: “Check your mail for the verification link.”

  3. The card is added to Qerko app and I can use it from now on.

Card authority perspective

  1. Qerko sends an authorization request to the authority which is assigned to the selected brand of the loyalty card. Card info and a list of verified emails is included in the request. Card info can be any set parameters from the physical loyalty card, or it can be a code generated by the personnel of the restaurant. The specific form is configured per card brand.

  2. The authority processes the request and responds with a response. If the response contains the final authorization result, the process has ended. If the response doesn’t contain the final authorization result, Qerko will await the result anytime in the future. Feel free to use any two-factor authentication method (ex: email with verification link). Qerko will wait. When the result is available, the authority submits it to the Qerko. Qerko will notify the customer about the result.

  3. The end. The customer can use his loyalty card from now on.

Customers perspective

  1. I pick my items and choose to use my previously added loyalty card. The Qerko app shows me my bill, but I can not modify items any more and there is a form which I have to fill in. Alternatively I can go back and start it over or opt not to use my loyalty card.

  2. I submit the required information until there is no form to fill in any more. Qerko app displays the bill with the applied bonus. It can be a discount or no bonus at all, because I have opted to receive loyalty points.

  3. I make the swipe gesture to proceed with the payment.

  4. The bill is paid. I can go home now :)

POS perspective

  1. Qerko requests POS to create a new individual bill with exact items. The request contains the id of the source bill, loyalty card token (result of authorization) and items. POS responds with an individual bill structure. It can contain a set of questions which have to be answered in order to proceed.

  2. The customer submits responses and Qerko forwards them to POS along with the individual bill id. POS responds with a recalculated individual bill which may contain another set of questions. We call this “the negotiation”, because the customer is negotiating with the POS. This step repeats until POS has returned no additional questions.

  3. The bill is paid like any other bill. If the customer has left this process anytime before this step, Qerko requests POS to cancel the individual bill. POS should, but doesn’t have to, return items to the original bill. The customer is returned back to the individual bill (if it exists) or to the original bill (if it exists) or message “Your bill was closed” will be displayed.

Authorization and usage

There are two problems which have to be addressed in order to get this extension to work. First problem is the authorization of the loyalty card. The second problem is the application of the loyalty card.

Methods

Card Authority Methods

We will need a card authority in this step. It can be the POS, or it can be an independent component or another POS instance. If the loyalty card works only in one restaurant, it can be the POS. If the loyalty card works in multiple restaurants, it will probably be an independent component. Card authority verifies the guest and his loyalty card. It also passes the authorization result to Qerko. It is connected to Qerko using websocket or long-polling connection, but it doesn’t have to implement standard POS methods.

authorizeLoyaltyCard

authorizeLoyaltyCard(request :LoyaltyCardAuthorizationRequest) :LoyaltyCardAuthorizationResponse

Qerko asks the card authority to authorize a loyalty card. This method returns the AuthorizationResponse structure.

ParameterTypeDescription
requestAuthorizationRequestAuthorization request described in the data structures section.
LoyaltyCardAuthorizationRequest

Qerko sends this structure to the Loyalty Card Authority. It contains properties which are needed to authorize the loyalty card.

PropertyTypeRequiredDescription
requestIdstringYesIdentifier of this request in GUIDv4 (opens in a new tab) format.
expirationstringYesExpiration of the request in ISO8601 (opens in a new tab) extended format. If the request results in a PENDING state, this is the timestamp of the request expiration. The result won’t be accepted after this expiration. Example: 2019-04-13T00:22:57+01:00
loyaltyCardInfoobjectYesObject with unspecified properties. Exact properties will depend on the configuration for the card brand. It carries data readable from the physical loyalty card. Example: { “number”: “1234 5678 9012” }
emailsstring[]YesA set of known and verified emails of the customer. Lower-cased and hashed using SHA1 for privacy reasons (GDPR).
languagestringYesA suggested language for the message in response. In ISO639-1 (opens in a new tab) format.
hmacKeystringYesA string to be used as the HMAC key for signature. It must not leak to the customer in any form. See below.
callbackUrlstringYesURL where to navigate the customer to successfully finish the request. Example (opens in a new tab) The Loyalty Card Authority has to add query parameters token and signature. Signature is SHA1 HMAC in hex encoding. Data is the token, hmacKey is provided. See above. Result url (opens in a new tab)

loyaltyCardAuthorizationFinished

loyaltyCardAuthorizationFinished(response :LoyaltyCardAuthorizationResponse) :null

REST-API alternative: POST /api/v2/card-authority/loyalty-card-authorization-finished - request body contains the LoyaltyCardAuthorizationResponse structure.

Card authority should call this method when the customer completes the authentication challenge and the authority has the final result. When called with response.result = PENDING then the response is treated as UNAUTHORIZED.

ParameterTypeDescription
responseLoyaltyCardAuthorizationResponseAuthorization response described in data structures section.
LoyaltyCardAuthorizationResponse

Loyalty Card Authority returns this structure in the authorizeLoyaltyCard method or it is used as an argument for the loyaltyCardAuthorizationFinished method.

It contains the authorization result.

PropertyTypeRequiredDescription
requestIdstringYesIdentifier of this request in GUID v4 (opens in a new tab) format. It was received in the LoyaltyCardAuthorizationRequest.
resultstringYesEnum: AUTHORIZED - final result - successfully authorized UNAUTHORIZED - final result - unsuccessful authorization PENDING - final result will be sent in the future
loyaltyCardTokenstringYesIf result = PENDING Token is ignored If result = UNAUTHORIZED Token is ignored If result = AUTHORIZED Token must be a non-empty string. POS should recognize the customer based on this string. Example: “abc-123-foo-bar”
messagestringYesIf result = PENDING Message contains instructions for the customer If result = UNAUTHORIZED Message contains the reason why is the request unauthorized If result = AUTHORIZED Message is ignored Example: “Check your email for verification link”

Usage of the added card

The POS has to implement methods which allow Qerko and POS to negotiate an offer for the customer. POS can ask the user any additional questions. Many loyalty cards offer multiple possibilities so we need to figure out what the customer wants to do with it. Example: gain loyalty points vs. spend them.

startIndividualBill

startIndividualBill(idBill :string, loyaltyCardToken :string, items :BillItem[], language :string) :IndividualBillData

Qerko asks POS to start a new individual bill from the original bill with the specified loyalty card with specified items. This method returns an IndividualBillData structure.

ParameterTypeDescription
idBillstringIdentifier of the original non-individual bill
loyaltyCardTokenstringString which identifies the customer.It is the result of the card authorization.
itemsBillItem[]Items which should be transferred to the new individual bill. The same structures as in the base document.
languagestringA suggested language for questions in ISO 639-1 (opens in a new tab) format.
IndividualBillData

This structure represents an individual bill. It is a composite of Bill structure with a description of the offered bonus and a set of questions which needs to be answered before payment.

PropertyTypeRequiredDescription
individualBillBillYesBill which contains items. Effect of the loyalty card should be applied.
descriptionstringNoBrief description of the individual offer.
questionsIndividualQuestion[]NoDefault: [] A set of questions which need to be answered before
Special error codes

This section describes string values that can appear in potential Error.code, that have special meaning.

INVALID_LOYALTY_CARD_TOKEN ‒ Qerko app will announce that the loyalty card is invalid and suggest to the customer to reauthorize it.

BILL_NOT_CUSTOMIZABLE ‒ Qerko app will announce that the loyalty card can not be used with this bill.

updateIndividualBill

updateIndividualBill(idIndividualBill :string, answers :IndividualAnswer[]) :IndividualBillData

Qerko has answers for questions from the previous set. POS should modify the individual bill accordingly and return a new individual bill with or without questions. This method returns an IndividualBillData structure.

ParameterTypeDescription
idIndividualBillstringIdentifier of the individual bill which should be modified with provided answers. Another set of questions may be returned.
answersIndividualAnswer[]A set of answers for the actual set of questions.
IndividualBillData

This structure represents an individual bill. It is a composite of Bill structure with a description of the offered bonus and a set of questions which needs to be answered before payment.

PropertyTypeRequiredDescription
individualBillBillYesBill which contains items. Effect of the loyalty card should be applied.
descriptionstringNoBrief description of the individual offer.
questionsIndividualQuestion[]NoDefault: [] A set of questions which need to be answered before

cancelIndividualBill

cancelIndividualBill(idIndividualBill :string) :null

Qerko asks POS to cancel the individual bill. This is because the customer has left the negotiation session. POS should return items to the original bill. POS doesn’t have to cancel the individual bill. After this call the app checks all bills on the table and if the individual bill is found, the customer is returned to the individual bill. Else if the original bill is found, the customer is returned to the original bill. Else the app shows a message “Your bill was closed” and the customer is returned to the QR scanning screen.

This covers the situation when Alice starts her individual bill meanwhile Bob pays the rest of the original bill. In this case the original bill is closed so there is no bill to which individual items should be returned.

ParameterTypeDescription
idIndividualBillstringIdentifier of the individual bill which should be cancelled and items should be returned to the original, non-individual bill.

IndividualAnswer

This structure represents an answered question.

PropertyTypeRequiredDescription
idstringYesIdentifier of the question.
booleanbooleanNoCustomer’s response to the question. Required if dataType of related IndividualQuestion = “boolean”
numbernumberNoCustomer’s response to the question. Required if dataType of related IndividualQuestion = “number”
stringstringNoCustomer’s response to the question. Required if dataType of related IndividualQuestion = “string”