DocumentationLoyalty cards

Loyalty Cards

This page describes the loyalty card extension to the Qerko API. The extension allows customers to add their loyalty cards to the Qerko app and redeem benefits offered by restaurants. A card can work across multiple restaurants.

Usage Perspective

  1. The customer decides to use a loyalty card when paying with the Qerko app, so they add the card in the app. They select the card brand from the supported list and provide the requested card details.

  2. The Qerko app communicates the result, which can be one of the following:

    1. The card is authorized and ready for use.
    2. The card cannot be authorized and requires resolution.
    3. Additional action is necessary, for example “Check your email for the verification link.”
  3. After a successful outcome, the card is stored in the Qerko app for future use.

Card Authority Perspective

  1. Qerko sends an authorization request to the authority assigned to the selected card brand. The request includes card information and a list of verified customer emails. Card information can be any parameters from the physical card or a code generated by staff. The exact format is configured per card brand.

  2. The authority processes the request and returns a response. If the response contains the final result, the flow ends. Otherwise, Qerko waits for the result. The authority can trigger additional verification, such as a two-factor flow via email. Once the outcome is available, the authority submits it to Qerko, which notifies the customer.

  3. After authorization succeeds, the customer can use the loyalty card.

Customer Perspective

  1. The customer selects items and chooses to apply a saved loyalty card. The Qerko app shows the bill, locks item modifications, and prompts for any required inputs. The customer can go back or proceed without the card if needed.

  2. The customer submits the requested information until no additional forms remain. The Qerko app then displays the bill with the applied benefit, such as a discount or loyalty points.

  3. The customer confirms the payment.

  4. The bill is paid and the flow ends.

POS Perspective

  1. Qerko requests the POS to create a new individual bill with the specified items. The request contains the source bill ID, the loyalty card token (result of authorization), and the items. The POS responds with an individual bill structure, which may include follow-up questions that must be answered before payment.

  2. The customer submits responses and Qerko forwards them to the POS together with the individual bill ID. The POS recalculates the bill and can return another set of questions. This exchange is referred to as the negotiation, because the customer is effectively negotiating with the POS. The step repeats until the POS returns no additional questions.

  3. The bill is paid like any other bill. If the customer leaves the process before completing payment, Qerko requests the POS to cancel the individual bill. The POS should, but is not required to, return items to the original bill. The customer is then 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:

  1. Authorization of the loyalty card.
  2. 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.

ParameterTypeDescription
requestLoyaltyCardAuthorizationRequestAuthorization 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.

ParameterTypeDescription
responseLoyaltyCardAuthorizationResponseAuthorization 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.

PropertyTypeRequiredDescription
requestIdstringYesIdentifier of this request in GUID v4 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 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”
messagestringYesIf 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.

ParameterTypeDescription
idBillstringIdentifier of the original non-individual bill
loyaltyCardTokenstringString which identifies the customer. It is the result of the card authorization.
itemsBillItem[]Items to be transferred to the new individual bill. The same structures as in the base document.
languagestringSuggested 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.

ParameterTypeDescription
idIndividualBillstringIdentifier of the individual bill to be modified with the provided answers. Another set of questions may be returned.
answersIndividualAnswer[]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.

ParameterTypeDescription
idIndividualBillstringIdentifier 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.

PropertyTypeRequiredDescription
idstringYesIdentifier of the question.
booleanbooleanVariesCustomer’s response to the question. Required if dataType of related IndividualQuestion = “boolean”
numbernumberVariesCustomer’s response to the question. Required if dataType of related IndividualQuestion = “number”
stringstringVariesCustomer’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.

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

IndividualQuestion

This structure represents a question to be answered by the customer.

PropertyTypeRequiredDescription
idstringYesIdentifier of the question.
dataTypestringYesAnswer dataType - one of:
* 'boolean'
* 'number'
* 'string'
labelstringYesThe question in human-readable text. Will be used as the label for the form field for the answer.
descriptionstringNoPossible longer text to clarify the question.
optionsIndividualQuestionOption[]NoList of options that the customer can pick as their answer. Use this to create dropdowns.

IndividualQuestionOption

This structure represents a substructure of IndividualQuestion

PropertyTypeRequiredDescription
labelstringYesLabel for this option. Human-readable text for the customer.
booleanbooleanVariesValue for this option if dataType is “boolean”
numbernumberVariesValue for this option if dataType is “number”
stringstringVariesValue 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.

PropertyTypeRequiredDescription
requestIdstringYesIdentifier of this request in GUIDv4 format.
expirationstringYesExpiration 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
loyaltyCardInfoobjectYesObject 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" }
emailsstring[]YesA set of known and verified emails of the customer. Lower-cased and hashed using SHA1 for privacy reasons (GDPR).
languagestringYesSuggested language for the message in response. In ISO639-1 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 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? Contact techsupport@qerko.com for assistance.