> ## Documentation Index
> Fetch the complete documentation index at: https://docs.loyalty.xeniamoments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Decision log

> Every decision in the integration, with date, status and source, in chronological order.

Status legend: **Agreed** — settled between the parties on the given date.
**Proposed** — REKOM's Version 2 proposal (8 Oct 2026), awaiting confirmation.
**Superseded** — was agreed, later replaced; kept for traceability.
**Not chosen** — an alternative that was on the table and rejected on the given date; the reason is stated so it is not re-proposed.
**Directional** — a field name, enum value, header or structure used in this document for illustration; not aligned, REKOM adopts OnlinePOS's default.

Sources: *Doc V1* = OnlinePOS's Google Doc (28 Aug 2026) and REKOM's comments with
OnlinePOS's answers (3 Sep 2026); *Doc V1-sync* = the 4 Sep 2026 update;
*Loyalty thread* = "Rekom Loyalty Beskrivelse" e-mail thread (12 Aug – 7 Oct 2026);
*Nexi thread* = "Rekom | Nexi Engage integration" e-mail thread (14 Aug – 2 Sep 2026);
*7 Oct* = meeting notes, 7 Oct 2026; *Follow-up* = clarifications exchanged after the 7 Oct meeting.

| Date | Decision | Status | Source |
| - | - | - | - |
| 12 Aug 2026 | Order loyalty statuses `not_applicable`, `member_not_found`, `applied`, `unchanged`, `failed`. | Agreed | Loyalty thread |
| 12 Aug 2026 | Idempotency key / request ID on all calls; retries never duplicate or double-discount. | Agreed | Loyalty thread |
| 12 Aug 2026 | OnlinePOS never creates members in Nexi Engage; guest enrolment is REKOM's. | Agreed | Loyalty thread |
| 14 Aug 2026 | Two phases; Phase 2 requires Phase 1. | Agreed | Loyalty thread |
| 17 Aug 2026 | Activation per customer/venue and per module: Nexi alone gives lookup and stored loyalty ID; Nexi plus REKOM backend gives the basket flow. | Agreed | Loyalty thread |
| 17 Aug 2026 | Phase 1 stores the loyalty ID on the order as a tag (Nightpay pattern); no webhook in Phase 1. | Agreed | Loyalty thread |
| 17 Aug 2026 | Finalised transactions are immutable; no update endpoints; loyalty metadata written only during send/receive of the basket. | Agreed | Loyalty thread |
| 17 Aug 2026 | Discount shown as a line-level note under the product with the value shown separately; product receipt text untouched. | Agreed | Loyalty thread |
| 17 Aug 2026 | REKOM asks for line discounts only (no add/remove lines, no order discounts). | Superseded: V1 §7 (28 Aug) kept the broader set and V2 keeps it; line discounts remain REKOM's own practice | Loyalty thread |
| 17 Aug 2026 | REKOM's preference: store enrollment owned by REKOM with minimal OnlinePOS surface. | Superseded 2 Sep 2026 by Option 1 for the Viking/DAM path; still REKOM's stance for non-terminal channels | Nexi thread |
| 27 & 31 Aug 2026 | `registerstore` at every terminal startup is acceptable; repeat returns harmless error 212. | Agreed (Nexi) | Nexi thread |
| 28 Aug 2026 | `loyaltyDiscountReference` dropped. | Superseded by the calculation GUID (7 Oct) | Loyalty thread |
| 28 Aug 2026 | OnlinePOS V1: asynchronous model with `basketId`, polling and callbacks. | **Not chosen** (4 Sep 2026): there is no user interaction during the call, so callbacks and polling only add latency and failure modes; replaced by the synchronous model | Doc V1 |
| 31 Aug 2026 | `storeId` = BAX ID, no prefix; 1 BAX = 1 terminal setup; REKOM enters it in an OnlinePOS field. | Agreed | Nexi thread |
| 31 Aug 2026 | Composite `storeId` with operator and environment prefix. | **Not chosen** (same day): one BAX is already one terminal setup and one environment, so the prefix added nothing | Nexi thread |
| 31 Aug 2026 | REKOM requests a synchronous model: no user interaction after card presentation; OnlinePOS proceeds with the sale if REKOM does not answer in time; extra data pulled later via the REST API. | Agreed 4 Sep | Loyalty thread |
| 31 Aug 2026 | DAM API-based enrollment (≈ 2 months at Nexi) not pursued now. | Parked | Nexi thread |
| 2 Sep 2026 | Store enrollment **Option 1**: "Integrations" tab with "Nexi Engage Store ID" in Backoffice terminal setup; REKOM fills in the BAX ID; terminal runs `registerstore` for all TIDs at every startup. | Agreed | Nexi thread |
| 2 Sep 2026 | Option 2: REKOM enrolls every BAX through an HQ terminal, OnlinePOS does nothing. | **Not chosen**: more complexity than the terminal enrolling at every boot (separate step per BAX, split ownership, no self-healing for new or replaced hardware) | Nexi thread |
| 2 Sep 2026 | Manual enrollment by Nexi per store (DAM, Nexi Engage database, Baxbis). | **Not chosen**: manual work for every new BAX; error-prone by Nexi's own assessment (20 Aug 2026) | Nexi thread |
| 2 Sep 2026 | Member lookup is BAXI action 193 `getasset` with `cardref` only; no token on terminals. Softpay calls Nexi Engage directly, no enrollment. | Agreed (implicit) | Nexi thread |
| 3 Sep 2026 | Staff only see the normal card-payment button; whether lookup/loyalty runs is an OnlinePOS setup detail. | Agreed | Doc V1 comments |
| 3 Sep 2026 | Discounts are dedicated POS discount data, never a free-text product at price 0. | Agreed | Doc V1 comments |
| 3 Sep 2026 | OnlinePOS stores the discount data needed to reproduce receipts. | Agreed | Doc V1 comments |
| 3 Sep 2026 | REKOM pulls transactions via the existing REST API ("we sync orders anyway"). | Agreed, confirmed 7 Oct | Doc V1 comments |
| 3 Sep 2026 | Order-level discounts are possible in principle, but REKOM must split them onto the lines: revenue is registered per line and some products (e.g. cigarettes) may not legally be discounted. OnlinePOS places order discounts visually at the bottom of the receipt, as for discount campaigns. | Agreed | Doc V1 comments (§8) |
| 3 Sep 2026 → V2 | Consequence: OnlinePOS sends, per line, whether the product may legally be discounted (`noDiscount`, from the product's `no_discount` setting) plus `noPercentageDiscount`; both mandatory. | Information required by REKOM; names directional | This document |
| 4 Sep 2026 | OnlinePOS accepts the synchronous flow; callbacks, `basketId` and polling removed. On timeout/failure the sale proceeds with the original basket, no new card approval, order's loyalty status `failed` (the sale completes). | Agreed | Doc V1-sync |
| 6 Oct 2026 | All loyalty and discount logic in the REKOM backend; POS/mPOS calculate nothing and replace the basket with the returned one. | Agreed | Loyalty thread (estimate assumptions) |
| 6 Oct 2026 | POS's existing discount system is unchanged; REKOM discounts reference a campaign ID that exists in POS (local or generic third-party campaign); REKOM follows POS's combination rules. | Agreed; resolved after 7 Oct to the generic type with no campaign ID (see below) | Loyalty thread |
| 6 Oct 2026 | Order discounts come back with a local campaign ID or are converted by REKOM to line discounts before the basket is returned. | Agreed | Loyalty thread |
| 6 Oct 2026 | BAXI prepurchase used as today; no change to the payment flow. | Agreed | Loyalty thread |
| 6 Oct 2026 | No new print layouts; discounts appear only as note lines under the affected products. | Agreed | Loyalty thread |
| 6 Oct 2026 | Audit and reporting handled in REKOM; POS has no structures for REKOM-specific values. | Agreed; partly refined 7 Oct (GUID) | Loyalty thread |
| 7 Oct 2026 | The basket REKOM returns is authoritative; agreed "no change" response; REKOM is the source of truth for all discount calculation. | Agreed | 7 Oct |
| 7 Oct 2026 | OnlinePOS's audit trail unchanged; loyalty and discount reporting in REKOM. | Agreed | 7 Oct |
| 7 Oct 2026 | POS/mPOS generate a GUID per basket calculation, sent to REKOM and available on the transaction via the REST API. | Agreed | 7 Oct |
| 7 Oct 2026 | Free-text field at the bottom of the receipt for order discounts; informational, not in reporting. | Agreed | 7 Oct |
| 7 Oct 2026 | REKOM writes Version 2 of the project description and sends it for review. | Agreed | 7 Oct |
| After 7 Oct 2026 | Loyalty discounts carry **no campaign ID**. Each discount carries a predefined, semantic string identifying the catch-all third-party-loyalty discount type (`lineDiscountCode`). Exact string to be confirmed (O2). | Agreed (approach) | Follow-up |
| After 7 Oct 2026 | A per-venue "REKOM Loyalty" discount campaign referenced by campaign ID on every loyalty line. | **Not chosen**: replaced by the predefined catch-all discount code, which needs no per-venue provisioning or campaign sync | Follow-up |
| After 7 Oct 2026 | The common loyalty/order ID (calculation GUID) is exposed in the REST API through **meta attributes** on the order. | Agreed | Follow-up |
| After 7 Oct 2026 | The order sent to REKOM carries the BAX number (venue identity) and the terminal identifier, so REKOM can attribute every order to a venue and till. | Agreed | Follow-up |
| 8 Oct 2026 | Phase 2 keeps every V1 §7 operation (price update, line discounts, add/remove/split lines, order-level discounts with REKOM-supplied allocation). REKOM practice: member prices and partial-quantity benefits as amount discounts. Field names `overrideUnitPrice`, `addedByLoyalty`, `splitFromLineId`, `discountCode` are illustrative. | Scope agreed (V1); names directional | This document |
| 8 Oct 2026 | One post-sale event `POST /v1/onlinepos/sale` with statuses `applied`, `unchanged`, `member_not_found`, `failed`, `cancelled` replaces the three V1 endpoints. | Proposed | This document |
| 8 Oct 2026 | Latency: p95 ≤ 150 ms, p99 ≤ 250 ms; POS timeout 500 ms per attempt, one connect-retry, hard cap 3 s. | Proposed | This document |
| 8 Oct 2026 | HMAC-SHA256 request signing (`OnlinePOS-Signature`), secret per environment, TLS 1.2+. No scheduled rotation; REKOM asks for self-service access to swap the secret and keeps old and new active with an overlap during a swap. | Proposed | This document |
| 8 Oct 2026 | Identifier naming: `loyaltyId` in payloads; context fields `venueId`, `baxId`, `cashRegisterId`, `terminalId`, `clerkNumber`, `channel`. | Directional: the information is required, the names follow OnlinePOS defaults | This document |
| 8 Oct 2026 | Money as integer minor units with ISO 4217 `currency`; VAT never sent or returned. | Proposed | This document |
| 8 Oct 2026 | Basket change after calculation: new GUID with `supersedesCalculationId`; loyalty ID reused; unsettled calculations expire after 30 minutes. | Proposed | This document |
| 8 Oct 2026 | Discounts already on the incoming basket (staff, product price, order) are REKOM's to keep or swap: a larger loyalty discount replaces the existing one; OnlinePOS applies the returned basket as-is. | REKOM logic, following "returned basket authoritative" (7 Oct); OnlinePOS to confirm (O4) | This document |
| 8 Oct 2026 | Rounding: `round_half_up` per line in minor units, computed by REKOM; OnlinePOS validates identities only. | Proposed | This document |
| 8 Oct 2026 | Discount code value `loyalty` as the predefined string; loyalty ID and loyalty status stored as further meta attributes next to the GUID. | Proposed (value directional, OnlinePOS names it) | This document |
| 8 Oct 2026 | Environments: separate hosts and secrets; test venues ↔ staging; cross-environment calls answered `422 venue_not_configured`. | Proposed | This document |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.