Skip to content

Loyalty CRM API --- trimmed reference for the webshop integration ​

Butlers Hungary (Vidámnyik Kft.) --- Invitation to Tender, Lot 2 --- Q&A attachment Extract of the current CRM API (Laurel, document "CRM_API_eng_v2"), reduced to the functions relevant to an online loyalty integration. Functions for tills, gift cards, user/shop administration and inventory are omitted. Confidential --- for bid preparation only.

0. What this is for ​

The Hungarian loyalty programme lives in the Laurel CRM that also serves the Laura tills. The webshop platform today talks to this CRM to look up a member, calculate the discount, lock the card during checkout and record the transaction. The functions below are what a platform needs to (a) run the current programme online, (b) migrate or mirror member data, and (c) keep both channels consistent.

1. Protocol ​

  • JSON-RPC 1.0 over HTTP POST; UTF-8.
  • Every call carries shopID (first param), tillID (second param) and hash (last param). The webshop is registered as its own shop/till pair.
  • id is chosen by the caller (timestamp recommended) and echoed in the response.
  • Dates yyyy-mm-dd, timestamps yyyy-mm-dd hh:mm:ss.
  • Security: shared secrets. hash = SHA-256(serverPassphrase + clientPassphrase + <data>), where <data> is function-specific (listed per function). Responses are unsigned. There is no nonce or timestamp in the hash; treat the link as a trusted-network integration.

Error codes (all functions) ​

1000 card expired · 1001 card inactive · 1002 invalid parameter · 1003 invalid card number · 1013 card locked (by other) · 1015 missing card lock · 1016 missing card id · 1017 amount too high · 1018 card already active · 1019 invalid amount · 1020 card used · 1021 card already deactivated · 1022 card blocked · 1023 card not deactivated · 2000 database error · 9996 bad data format · 9997 unknown client · 9998 hash error · 9999 unknown command

Response envelope everywhere: { "result": {...}, "error": "<code:message>", "id": x }.

2. Programme parameters ​

DiscQuery --- discount tiers ​

{ "method":"DiscQuery", "params":[shopID, tillID, "<hash>"], "id":x } --- hash from: passphrase Response: { "count": n, "lines": [[discountId, "discount%", bottomLimit, topLimit], …] } The tiers map cumulated points (spec_point1) to a permanent discount %. This is the mechanic the tender describes as "points → permanent % discount".

DictQuery --- code lists (read-only) ​

{ "method":"DictQuery", "params":[shopID, tillID, datasetId, "<hash>"], "id":x } --- hash from: passphrase + datasetId (as text) Dataset ids: 2 highest education, 3 position, 4 marital status. Needed only to decode study_level, position, marital_status in member records.

3. Member lookup and checkout ​

LoyCardQuery --- look up a card, simulate a purchase ​

{ "method":"LoyCardQuery", "params":[shopID, tillID, "<cardnumber>", pointsToAdd, "<hash>"], "id":x } --- hash from: passphrase + cardnumber Does not add points; pointsToAdd is used to compute discount, next_discount and points_to_next_discount for the basket at hand (the tills carry no business logic, so the CRM does the maths). Response fields: nr, valid_from, valid_to, banned, ban_date, loy_points (spendable balance), spec_point1 (cumulated points --- tier basis), active, first_store_nr, member data (cust_name, cust_zip, cust_city, cust_addr, maiden_name, gender [F = male, N = female], mobile_nr, e_mail, birthday, study_level, position, marital_status, nameday [mmdd], comment, structured address fields cityrange, addresstype, housenumber, building, stairway, level, door, taxnr), last_mod, last_partner_mod, last_trans, discount, next_discount, points_to_next_discount. Errors: 1003, 2000, 9997, 9998, 9999.

LockCard / UnlockCard --- reserve the card for one transaction ​

{ "method":"LockCard", "params":[shopID, tillID, "<cardnumber>", "<transactionNumber>", "<hash>"], "id":x } --- hash from: passphrase + cardnumber { "method":"UnlockCard", "params":[shopID, tillID, "<cardnumber>", "<transactionNumber>", "<hash>"], "id":x } --- hash from: passphrase + cardnumber + transactionNumber Response: { "nr": "<cardnumber>" }. Errors: 1003, 1013 (locked by other), 2000, 9997, 9998, 9999. A card locked by one channel cannot be used by another until LoyCardUse or UnlockCard releases it --- this is the current "real-time online/offline consistency" mechanism.

LoyCardUse --- book the transaction ​

{ "method":"LoyCardUse", "params":[shopID, tillID, "<cardnumber>", pointsReceived, pointsUsed, "discount%Received", discountValueReceived, "<hash>"], "id":x } --- hash from: passphrase + cardnumber + pointsReceived + pointsUsed Records points collected, points redeemed and the discount granted in one call; the response returns the card header with the new loy_points / spec_point1. Errors: 1003, 1021, 2000, 9997, 9998, 9999.

Typical online checkout sequence today: LoyCardQuery (with the basket's points) → show discount → LockCard → payment → LoyCardUse (or UnlockCard if the order is abandoned).

SaleSet --- push receipt lines (optional, statistics) ​

{ "method":"SaleSet", "params":[shopID, tillID, [[ "timestamp","shopId","tillId","cashier","receiptId","warehouseId","transactionType","transactionId", [["articleId", qty, "description", originalPrice, finalPrice], …] ], …], rowCount, "<hash>"], "id":x } --- hash from: passphrase + rowCount; max 1000 articles per call. Lets the CRM keep article-level purchase history per member (SaleQuery reads it back). Not required for the discount mechanic itself.

4. Enrolment and member data ​

LoyCardActivation --- activate a card without customer data ​

{ "method":"LoyCardActivation", "params":[shopID, tillID, "<cardnumber>", "<hash>"], "id":x } --- hash from: passphrase + cardnumber. Errors incl. 1018 (already active).

LoyCardActivationExtended --- activate with customer data (online enrolment) ​

{ "method":"LoyCardActivationExtended", "params":[shopID, tillID, "<cardnumber>", "<name>", "<zip>", "<city>", "<street, no>", "<maiden name>", "<gender F/N>", "<mobile>", "<e-mail>", "<birthday>", studyLevelId, positionId, maritalStatusId, "<nameday>", "<comment>", "<hash>"], "id":x } --- hash from: passphrase + cardnumber Response = card header + member data + partner_id (the new CRM partner id). Cards are pre-printed; a card does not exist in the CRM until it is activated with its printed number (in stores by scanning the card). Activating a number that was already activated returns 1018.

LoyCardUpdate --- edit member data ​

Same parameter list as LoyCardActivationExtended with method LoyCardUpdate; hash from: passphrase + cardnumber. Returns the full record.

Administrative card operations (exist, not needed online) ​

LoyCardDeactivation, LoyCardBan, LoyCardReplace(oldCardnumber, newCardnumber) --- hash from passphrase + cardnumber(s); return the card header. Replacement moves the balance (transaction types 16/18).

5. History, bulk read and synchronisation ​

CardTransQuery / PartnerHistoryQuery --- transactions ​

{ "method":"CardTransQuery", "params":[shopID, tillID, "<cardnumber|%>", "timeFrom", "timeTill", typeFrom, typeTill, from, count, "<hash>"], "id":x } --- hash from: passphrase + cardnumber Response lines: [cardnumber, "timestamp", type, totalValue, "transactionId", discountValue, discount%, shopId, balanceBefore]. PartnerHistoryQuery (same signature) follows the member across card replacements. Transaction types: 3 gift-card payment · 6 points collected · 7 discount · 8 points used · 16/18 card replacement (credit/debit) · 99 points depreciated (expiry). Defaults when unfiltered: time 2000.01.01 00:00:00--3000.01.01 00:00:00, type 0--99. from/count page the result.

CardListQuery --- bulk list (migration / full reconciliation) ​

{ "method":"CardListQuery", "params":[shopID, tillID, "<cardnumber|%>", type, from, count, "<hash>"], "id":x } --- hash from: passphrase + cardnumber + type; type 5 = loyalty cards (0 all, 4 gift cards). Lines: [cardnumber, type, balance, active, banned, last_mod, last_partner_mod, last_trans] --- balance = spendable points.

CardUpdates --- cards changed since a timestamp (incremental sync) ​

{ "method":"CardUpdates", "params":[shopID, tillID, type, "fromTime", "until", from, count, "<hash>"], "id":x } --- hash from: passphrase + type + fromTime + until Returns full member records (same fields as LoyCardQuery, without the tier fields) for every card whose data or partner data changed in the window. This is the hook for mirroring the member base into the platform (e.g. nightly delta) and for the migration export.

6. Notes for bidders ​

  • Member identity is the card number; there is no e-mail-keyed lookup --- the platform must store the card number against the customer account.
  • Points are integers in HUF-denominated logic; discount tiers are read from DiscQuery, not hard-coded.
  • Omitted from this extract: gift-card functions (physical gift cards are store-only), user/shop/dictionary administration, inventory/stock functions. The full document is available to shortlisted bidders on request.