Receipt history migration
During transition to Loymax Loyalty Program (LP), a Company purchase history can be imported into Loymax Loyalty. As a result, customers will see their purchase history from the previous loyalty program.
This article presents a simplified integration contract. The format is used when migrating historical receipts from external loyalty programs for display in personal accounts and CRM systems. The description focuses on the historical data migration scenario and does not cover all Loymax integration capabilities. Examples are provided in simplified form and reflect minimal valid structures.
Company data is transmitted to Loymax via a special utility and the messaging broker Apache Kafka. The utility converts the JSON file provided by the Company into a historical record model. The sender publishes the message to Kafka in the topic hist-items-records. The consumer HistoryItemsConsumer reads the message, converts it to protobuf format, and writes it to the History database. As a result, when accessing the Loymax history service via API in the Admin Panel, Personal Account, or Mobile App, the customer's receipt history is displayed.
Data processing speed
The size of the data batch processed by the utility is fixed and equals 100. The optimal batch size for the HistoryItemsConsumer consumer is 1000. The processing time per message reaches 0.36 ms. Increasing the batch size in consumer settings increases processing time: 0.52 ms per message at a batch size of 10,000. Parallel operation of the utility and consumer reduces processing time to 0.22 ms per message.
Types of purchases to import
| Purchase without detailed discounts and bonus points | Receipt with item composition and total amount without revealing discount, accrual, and deduction mechanics. |
| Purchase with line-item discounts | Receipt where applied discounts are recorded for individual items. |
| Purchase with line-item bonus points (with multi-currency support) | Receipt where bonus accruals are reflected for specific items. |
| Purchase with bonus points deduction | Receipt where the customer used bonus points to pay part of the purchase. |
| Separate accrual or deduction operations without a purchase | Bonus operations not linked to a specific receipt (e.g., manual corrections or expiration). |
Structure of transmitted data
When transmitting purchase data, a single structure is used, including the following logical blocks:
- General information about the purchase event.
- Data about the purchase itself.
- Receipt composition (item positions).
- Discounts, accruals, and deductions (if applicable).
- Payment information (if necessary).
- Additional attributes and auxiliary data (optional).
Each of the above blocks is described below, specifying required and optional parameters.
| Field | Required | Data Type | Description |
|---|---|---|---|
| externalId | Required | Guid | Unique identifier of this history record |
| DateTime | Required | DateTime | Date and time of the event |
| Type | Required | string | Event type |
| UserId | Optional | int | Identifier of the customer associated with the event |
| CustomerUid | Required | Guid | Internal customer identifier, unique within the System |
| Identity | Required | string | Additional data allowing identification of the event. Fill with customer card number |
| Withdraw | Optional | WithdrawDataViewModel | Deduction (manual) |
| Reward | Optional | RewardDataViewModel | Accrual (manual) |
| Description | Optional | string | Description for display in history |
| LocationId | Optional | Guid | Point of sale location identifier where the purchase was made. Not recommended to fill |
| PartnerId | Optional | Guid | Company identifier, constant |
| BrandUid | Optional | Guid | Uid of the brand where the purchase occurred, often a constant |
| HistoryPurchase | Required | HistoryPurchaseDataViewModel | Historical purchase data. See HistoryPurchaseDataViewModel model below |
| EventDateTime | Required | long | File upload date and time. Fill current date in ticks |
| LoyalityUid | Required | Guid | External Loyalty Program identifier, constant |
| historyVersion | Required | HistoryVersionType | Information about the history record version (database table where data from the uploaded file is written). Should be filled with value: V2 |
| source | Required | string | Record source information. When saving data from Loymax, leave this field empty. When importing external data, fill with any value, then the history record is marked with Imported=true. |
Below the nested models for required fields of the general structure are listed and described. These also include both required and optional fields.
General purchase information: HistoryPurchaseDataViewModel
| Field | Required | Data Type | Description |
|---|---|---|---|
| ExternalPurchaseId | Required | string | External purchase identifier |
| Amount | Required | decimal | Purchase amount after discounts |
| CurrencyUid | Required | string | External POS currency identifier (default POS currency: euros). One currency can be passed for all purchases |
| MerchantUid | Required | Guid | External point of sale identifier. One point of sale can be passed for all purchases |
| DeviceUid | Required | Guid | External POS identifier. One POS terminal can be passed for all purchases |
| ChequeItems | Required | HistoryChequeItemViewModel | Information about items in the receipt. See HistoryChequeItemViewModel model below |
| Withdraws | Required | WithdrawDataViewModel | Deductions within the purchase. See WithdrawDataViewModel model below |
| Rewards | Required | RewardDataViewModel | Accruals within the purchase. See RewardDataViewModel model below |
| IsRefund | Optional | bool | Whether the purchase is a refund. If no refunds, value: false |
| ChequeNumber | Required | string | Receipt number |
| ChequeAdditionalAttributes | Optional | ChequeAdditionalAttributeViewModel | Information about additional receipt attributes. Not recommended to transmit |
| State | Required | OperationState | Purchase state. Always pass value: Confirmed |
| AdditionalParams | Optional | string | Additional purchase parameters |
| Pays | Optional | PayModel | Payment methods. Fill if needed to specify what portion was paid with POS currency (euros) |
| Activities | Optional | Activity | Activities. Not recommended to transmit |
| DeviceEmulation | Optional | bool | Indicator whether the purchase was made on a test POS terminal. If transmitted, value always: false |
| Operations | Optional | PurchaseOperation | Operations |
| Coupons | Optional | Coupon | Coupons |
| ExternalPurchaseUid | Optional | string | Purchase identifier |
- Fields Withdraws and Rewards in the model are marked as required, despite potentially being empty arrays.
- Field IsRefund is used to transmit refunds during migration (value true if transmitted).
Receipt item information: HistoryChequeItemViewModel
| Field | Required | Data Type | Description |
|---|---|---|---|
| PositionId | Required | int? | Receipt position. Filled as sequential number within each receipt |
| Description | Optional | string | Description |
| Quantity | Optional | decimal | Quantity. If not passed, 0 will be displayed |
| Unit | Optional | string | Unit of measure |
| Amount | Required | decimal | Amount after discount deduction |
| ItemId | Optional | string | External product identifier (article) |
| Discounts | Required (conditional) | Discount | Discounts provided on receipt positions. Required if line-item detail is needed. See Discount model below |
| commonCode | Optional | string | Common code of the item |
| attributes | Optional | string | Item attributes. Not recommended to transmit |
| internalGoodId | Optional | int | Internal product identifier |
Preference model: Discount
This model is used only when line-item discount detail is required (discount detail/payment detail/bonus points detail) and is included in the HistoryChequeItemViewModel model.
| Field | Required | Data Type | Description |
|---|---|---|---|
| DiscountType | Required | PositionDiscountType | Type of preference provided. See PositionDiscountType model below |
| OfferId | Required | int | Internal offer identifier. Value must not equal 0. Pass identifier of a offer specifically created in the System; one can be created and passed as a constant |
| OfferVersionId | Required | int | Internal version identifier of the offer. Value must not equal 0. Pass identifier of a offer version specifically created in the System; one can be created and passed as a constant |
| Amount | Required | decimal | Amount of preference provided in virtual currency (if preference type: CalculatedCashback/PartnerCashback or CalculatedPayment) or in POS currency (if preference type: CalculatedDiscount/PartnerDiscount) |
| CurrencyId | Required | int? | Preference discount currency identifier. Must pass a currency that actually exists in the System: monetary or any virtual currency |
| CashAmount | Required | decimal? | Discount amount in POS currency (if preference type: CalculatedPayment). Do not fill if preference type: CalculatedCashback |
Type of preference provided: PositionDiscountType
One of the specified values below must be passed if the Discount model is transmitted (see above).
| Value | Name | Description |
|---|---|---|
| CalculatedCashback | Deferred bonus points | bonus points |
| CalculatedDiscount | Discount | Direct discount |
| PartnerDiscount | Partner discount | External/POS discount (passed from the point of sale POS terminal) |
| PartnerCashback | Partner bonus points | External/POS bonus points (passed from the point of sale POS terminal) |
| PositionCharge | Bonus points accrual | Bonus points accrual. This value is not used |
| CalculatedPayment | Payment | Deduction of bonus points for purchase |
Deduction information: WithdrawDataViewModel
This model is used to transmit line-item deductions within a purchase in HistoryPurchaseDataViewModel, required to fill, and also for manual deductions in the root object (field Withdraw), filling optional.
| Field | Required | Data Type | Description |
|---|---|---|---|
| MoneyAmount | Required | decimal? | Amount in POS currency (euros) |
| Description | Required | string | Operation description |
| PositionInfo | Optional | int, decimal | Distribution of deduction across positions |
| Amount | Required | decimal | Amount in bonus points |
| WithdrawType | Required | WithdrawType | Deduction type. See WithdrawType model below |
| CurrencyUid | Required | string | External virtual currency identifier |
Deduction types: WithdrawType
One of the specified values below must be passed if the WithdrawDataViewModel model is transmitted (see above).
| Value | Name | Description |
|---|---|---|
| Bonus | Bonuses | Bonus points deduction |
| Withdraw | Deduction | Deduction as a separate operation type |
Expiration | Expiration | Bonus points expiration |
Accrual information: RewardDataViewModel
This model is used to transmit accruals within a purchase in HistoryPurchaseDataViewModel, required to fill, and also for manual accruals in the root object (field Reward), filling optional.
| Field | Required | Type | Description |
|---|---|---|---|
| OfferExternalId | Required | string | External offer identifier |
| Description | Required | string | Detailed description specifying this accrual operation |
| PositionInfo | Optional | int, decimal | Distribution of accrual across positions (position number, amount) |
| Amount | Required | double? | Preference amount |
| RewardType | Required | RewardType? | Accrual type. See RewardType model below |
| CurrencyUid | Required | string | External virtual currency identifier (if accrual type: Bonus or Charging) or POS currency (if accrual type: Discount) |
Accrual type: RewardType
One of the specified values below must be passed if the RewardDataViewModel model is transmitted (see above).
| Value | Name | Description |
|---|---|---|
| Bonus | bonus points | Bonus points |
| Discount | Discount | Discount |
| Charging | Accrual | Additional bonus points accrual (within receipt, but not linked to positions) |