Loyalty Cards
This page describes an extension to the Qerko API for loyalty cards. It allows customers to add their loyalty cards to the Qerko app and enjoy benefits offered by restaurants. The card can work across multiple restaurants.
Usage Perspective
-
I want to use my loyalty card when I pay with the Qerko app, so I decide to add my loyalty card to the app. I select the brand of my loyalty card from the list of supported cards. The Qerko app asks me for some information about the card, which I fill in and submit.
-
The Qerko app presents me with the result of my request. It can be:
- The card is authorized and I can use it.
- The card is unauthorized for some reason, so I need to resolve the problem.
- I need to perform some additional action described by a message. For example: “Check your email for the verification link.”
-
The card is added to the Qerko app and I can use it from now on.
Card Authority Perspective
-
Qerko sends an authorization request to the authority assigned to the selected brand of the loyalty card. Card info and a list of verified emails are included in the request. Card info can be any set of parameters from the physical loyalty card, or a code generated by restaurant staff. The specific form is configured per card brand.
-
The authority processes the request and responds. If the response contains the final authorization result, the process ends. If not, Qerko waits for the result. You can use any two-factor authentication method (e.g., email with a verification link). When the result is available, the authority submits it to Qerko, which then notifies the customer.
-
That’s it. The customer can use their loyalty card from now on.
Customer Perspective
-
I pick my items and choose to use my previously added loyalty card. The Qerko app shows me my bill, but I can no longer modify items, and there is a form I have to fill in. Alternatively, I can go back and start over or choose not to use my loyalty card.
-
I submit the required information until there are no more forms to fill in. The Qerko app displays the bill with the applied bonus. It could be a discount or no bonus at all if I opted to receive loyalty points.
-
I make the swipe gesture to proceed with the payment.
-
The bill is paid. I can go home now.
POS Perspective
-
Qerko requests the POS to create a new individual bill with the exact items. The request contains the ID of the source bill, the loyalty card token (result of authorization), and the items. The POS responds with an individual bill structure. It can contain a set of questions that must be answered to proceed.
-
The customer submits responses, and Qerko forwards them to the POS along with the individual bill ID. The 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 the POS returns no additional questions.
-
The bill is paid like any other bill. If the customer leaves this process before this step, Qerko requests the POS to cancel the individual bill. The POS should, but does not have to, return items to the original bill. The customer is returned to the individual bill (if it exists), the original bill (if it exists), or sees the message “Your bill was closed.”
Authorization and Usage
There are two problems to address for this extension to work:
- Authorization of the loyalty card.
- Application of the loyalty card.
Methods
Card Authority Methods
A card authority is needed for this step. It can be the POS, 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. The card authority verifies the guest and their loyalty card. It also passes the authorization result to Qerko. It is connected to Qerko using a WebSocket or long-polling connection, but it does not 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.
Parameter | Type | Description |
---|---|---|
request | LoyaltyCardAuthorizationRequest | Authorization request described in the data structures section. |
loyaltyCardAuthorizationFinished
loyaltyCardAuthorizationFinished(response: LoyaltyCardAuthorizationResponse): null
REST-API alternative: POST /api/v2/card-authority/loyalty-card-authorization-finished - request body contains the LoyaltyCardAuthorizationResponse structure.
The 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, the response is treated as UNAUTHORIZED.
Parameter | Type | Description |
---|---|---|
response | LoyaltyCardAuthorizationResponse | Authorization response described in the data structures section. |
LoyaltyCardAuthorizationResponse
The card authority returns this structure in the authorizeLoyaltyCard method or uses it as an argument for the loyaltyCardAuthorizationFinished method.
It contains the authorization result.
Property | Type | Required | Description |
---|---|---|---|
requestId | string | Yes | Identifier of this request in GUID v4 format. It was received in the LoyaltyCardAuthorizationRequest. |
result | string | Yes | Enum: AUTHORIZED (final result - successfully authorized), UNAUTHORIZED (final result - unsuccessful authorization), PENDING (final result will be sent in the future) |
loyaltyCardToken | string | Yes | If result = PENDING or UNAUTHORIZED, token is ignored. If result = AUTHORIZED, token must be a non-empty string. The POS should recognize the customer based on this string. Example: “abc-123-foo-bar” |
message | string | Yes | If result = PENDING, message contains instructions for the customer. If result = UNAUTHORIZED, message contains the reason why the request is unauthorized. If result = AUTHORIZED, message is ignored. Example: “Check your email for verification link” |
Usage of the Added Card
The POS must implement methods that allow Qerko and the POS to negotiate an offer for the customer. The POS can ask the user additional questions. Many loyalty cards offer multiple possibilities, so we need to determine what the customer wants to do with it (e.g., gain loyalty points vs. spend them).
startIndividualBill
startIndividualBill(idBill: string, loyaltyCardToken: string, items: BillItem[], language: string): IndividualBillData
Qerko asks the POS to start a new individual bill from the original bill with the specified loyalty card and items. This method returns an IndividualBillData structure.
Parameter | Type | Description |
---|---|---|
idBill | string | Identifier of the original non-individual bill |
loyaltyCardToken | string | String which identifies the customer. It is the result of the card authorization. |
items | BillItem[] | Items to be transferred to the new individual bill. The same structures as in the base document. |
language | string | Suggested language for questions in ISO 639-1 format. |
Special Error Codes
This section describes string values that can appear in Error.code and have special meaning.
INVALID_LOYALTY_CARD_TOKEN
‒ The Qerko app will announce that the loyalty card is invalid and suggest the customer reauthorize it.
BILL_NOT_CUSTOMIZABLE
‒ The Qerko app will announce that the loyalty card cannot be used with this bill.
updateIndividualBill
updateIndividualBill(idIndividualBill: string, answers: IndividualAnswer[]): IndividualBillData
Qerko has answers for questions from the previous set. The POS should modify the individual bill accordingly and return a new individual bill with or without questions. This method returns an IndividualBillData structure.
Parameter | Type | Description |
---|---|---|
idIndividualBill | string | Identifier of the individual bill to be modified with the provided answers. Another set of questions may be returned. |
answers | IndividualAnswer[] | A set of answers for the current set of questions. |
cancelIndividualBill
cancelIndividualBill(idIndividualBill: string): null
Qerko asks the POS to cancel the individual bill. This is because the customer has left the negotiation session. The POS should return items to the original bill. The POS does not have to cancel the individual bill. After this call, the app checks all bills on the table. If the individual bill is found, the customer is returned to it. If the original bill is found, the customer is returned to the original bill. Otherwise, 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 while 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.
Parameter | Type | Description |
---|---|---|
idIndividualBill | string | Identifier of the individual bill to be cancelled and items to be returned to the original, non-individual bill. |
Data Structures
IndividualAnswer
This structure represents an answered question.
Property | Type | Required | Description |
---|---|---|---|
id | string | Yes | Identifier of the question. |
boolean | boolean | Varies | Customer’s response to the question. Required if dataType of related IndividualQuestion = “boolean” |
number | number | Varies | Customer’s response to the question. Required if dataType of related IndividualQuestion = “number” |
string | string | Varies | Customer’s response to the question. Required if dataType of related IndividualQuestion = “string” |
IndividualBillData
This structure represents an individual bill. It is a composite of the Bill structure with a description of the offered bonus and a set of questions that need to be answered before payment.
Property | Type | Required | Description |
---|---|---|---|
individualBill | Bill | Yes | Bill which contains items. The effect of the loyalty card should be applied. |
description | string | No | Brief description of the individual offer. |
questions | IndividualQuestion[] | No | Default: [] A set of questions that need to be answered before payment. |
IndividualQuestion
This structure represents a question to be answered by the customer.
Property | Type | Required | Description |
---|---|---|---|
id | string | Yes | Identifier of the question. |
dataType | string | Yes | Answer dataType - one of: * 'boolean' * 'number' * 'string' |
label | string | Yes | The question in human-readable text. Will be used as the label for the form field for the answer. |
description | string | No | Possible longer text to clarify the question. |
options | IndividualQuestionOption[] | No | List of options that the customer can pick as their answer. Use this to create dropdowns. |
IndividualQuestionOption
This structure represents a substructure of IndividualQuestion
Property | Type | Required | Description |
---|---|---|---|
label | string | Yes | Label for this option. Human-readable text for the customer. |
boolean | boolean | Varies | Value for this option if dataType is “boolean” |
number | number | Varies | Value for this option if dataType is “number” |
string | string | Varies | Value for this option if dataType is “string” |
LoyaltyCardAuthorizationRequest
Qerko sends this structure to the Loyalty Card Authority. It contains properties needed to authorize the loyalty card.
Property | Type | Required | Description |
---|---|---|---|
requestId | string | Yes | Identifier of this request in GUIDv4 format. |
expiration | string | Yes | Expiration of the request in ISO8601 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 |
loyaltyCardInfo | object | Yes | Object with unspecified properties. Exact properties depend on the configuration for the card brand. It carries data readable from the physical loyalty card. Example: { “number”: “1234 5678 9012” } |
emails | string[] | Yes | A set of known and verified emails of the customer. Lower-cased and hashed using SHA1 for privacy reasons (GDPR). |
language | string | Yes | Suggested language for the message in response. In ISO639-1 format. |
hmacKey | string | Yes | A string to be used as the HMAC key for signature. It must not leak to the customer in any form. See below. |
callbackUrl | string | Yes | URL where to navigate the customer to successfully finish the request. Example The Loyalty Card Authority must add query parameters token and signature. Signature is SHA1 HMAC in hex encoding. Data is the token, hmacKey is provided. See above. Result url |
Need help? If you get stuck or have questions, email us at techsupport@qerko.com—we’re here for you!