Skip to main content

Receiving the events

Reconciliation publishes what happens to till audits and store days as events. An external system subscribes through External Events. Hii Retail services subscribe to the Pub/Sub topics directly.

External Events sourceVersionPub/Sub topicPublished when
REC: Reconciliation completed (reconciliation-completed)v2rec.public.event.reconciliation-completed.v2a till audit is approved, by a count within the limit or by approval with an explanation
REC: Reconciliation rejected (reconciliation-rejected)v2rec.public.event.reconciliation-rejected.v2a count is outside the limit, once per attempt
REC: Reconciliation recount (reconciliation-recount)v2rec.public.event.reconciliation-recount.v2a completed till audit is recounted
REC: Reconciliation change shift (reconciliation-change-shift)v1rec.public.event.reconciliation-change-shift.v1a till audit is completed: its deviation per shift
REC: Reconciliation end of day (reconciliation-end-of-day)v1rec.public.event.end-of-day-completed.v2a store's day is submitted and closed
REC: Cash balance (cash-balance)v1rec.public.event.cash-balance.v1nightly, where switched on: the expected cash left in each store

⚠ The end-of-day source is version v1 in External Events, and reads the Pub/Sub topic version v2. Subscribe to reconciliation-end-of-day in External Events, or to rec.public.event.end-of-day-completed.v2 on Pub/Sub. Both deliver the same message.

Each source's JSON Schema is linked from External Events. The schemas are also on the event format pages.

Which one to take:

  • Accounting and ERP: reconciliation-end-of-day, one message per store and business date with the totals per tender.
  • Following each till: reconciliation-completed and reconciliation-recount.
  • Loss prevention and statistics: add reconciliation-rejected for every failed attempt, and reconciliation-change-shift for the deviation per shift.

Rules for consuming the events​

1. Expect duplicates, and know the key​

Delivery is at least once, so a message can arrive twice. Skip duplicates by:

EventDeduplication key
reconciliation-completedreconciliationId. A till audit completes once.
reconciliation-rejectedreconciliationId + timestamp. A till audit can be rejected several times, once per attempt.
reconciliation-recountrecountId
reconciliation-change-shiftreconciliationId
reconciliation-end-of-daybusinessUnitId + endOfDayDate + timestamp. A day can be summarised more than once.
cash-balancethe tenant + businessDate

2. Do not depend on the arrival order​

Events can arrive in a different order from the one they happened in. Order them by timestamp: the time of the count, approval or submission that produced the event.

3. Know which numbers are levels and which are changes​

EventFieldsMeaning
reconciliation-completed, -rejectedexpectedAmount, actualAmount, deviationAmount, and the quantitieslevels for this till audit. deviationAmount is counted minus expected, so negative means short.
reconciliation-recountexpectedAmount, actualAmountlevels, as recounted
reconciliation-recountamountCorrection, quantityCorrectionchanges: recounted minus the previous count of the same till audit
reconciliation-end-of-dayexpectedAmount, actualAmount, deviationAmount, and the quantitieslevels for the whole day
reconciliation-end-of-daythe fields ending in Deltachanges since the previous summary of the same store and date
reconciliation-change-shiftdeviationAmount / deviationAmountInShiftthe deviation at the count / the change during the shift

End of day: totals and deltas​

The first summary of a store's day carries the totals, with each delta equal to its total. If the day is summarised again, because more till audits for the date completed later, the next summary carries the new totals, with the deltas holding the difference from the previous summary.

🛑 Never add up the totals of two summaries for the same day. Either book the deltas of every summary, or replace the day with the totals of the newest one.

4. A recount changes a till audit you have already received​

A reconciliation-completed is not necessarily the last word on a till audit. A recount can follow, until the day is closed. If you book till audits individually, book the recount's corrections too. If you only take the end-of-day summary, recounts are already included in it, because a till audit cannot be recounted after the day is closed.

5. Read the business date, not the publishing time​

businessDate on a till audit, and endOfDayDate on a summary, is the trading day the figures belong to. A summary can be published days after its date. A till audit that spans midnight carries transactionTenderDates: its amounts split by the date of each transaction, for reports that need calendar days.

6. Read tolerantly​

  • Ignore fields you do not recognise. Fields are added within a version, and the published schemas do not reject extra fields.
  • Handle enum values you do not recognise. reconciliationType is CASH_DRAWER or CASH_CHANGER today.
  • Many amount and quantity fields are null when they do not apply: a tender counted only by quantity has no counted amount, and a read-only tender has no deviation. Only the fields the schema lists as required are always present.

Message attributes​

On Pub/Sub, each message carries these attributes, which you can use for filtering:

AttributeValue
Tenant-Idthe tenant
Business-Unit-Idthe store. Not set on cash-balance, which covers every store of a tenant.
Correlation-Ida trace ID for the request that led to the event

The events​

Reconciliation completed and rejected​

Both use the same format: the till audit, every tender with its expected, counted and allowed amounts, the counted items, the transaction IDs included, and who counted. reconciliationType tells a drawer from a cash changer. comment holds the explanation when the till audit was approved after a deviation.

{
"tenantId": "tenant-1",
"businessUnitId": "store-12",
"correlationId": "f3a6c1d0-5b8e-4a5e-9a7a-2f0d3c9b1e44",
"reconciliationId": "tenant-1-store-12-WORKSTATION-CASH_DRAWER-415",
"reconciliationType": "CASH_DRAWER",
"workstationId": "till-1",
"operatorId": null,
"userId": "8c1f0d0e-3b6a-4c39-9d0b-5c2e7f1a6b10",
"comment": null,
"timestamp": "2026-09-30T18:05:12.481Z",
"timezoneOffset": "+02:00",
"businessDate": "2026-09-30",
"tenders": [
{
"tenderId": "CASH-NOK",
"currencyId": "NOK",
"isReadOnly": false,
"initialBalance": 2000,
"expectedAmount": 1630,
"actualAmount": 1620,
"deviationAmount": -10,
"allowedDeviationAmount": 20,
"expectedQuantity": 3,
"actualQuantity": null,
"deviationQuantity": null,
"allowedDeviationQuantity": null,
"isCashChanger": false,
"denominations": [
{ "denominationValue": 500, "quantity": 2 },
{ "denominationValue": 200, "quantity": 3 },
{ "denominationValue": 20, "quantity": 1 }
]
}
],
"items": [],
"transactionIds": ["…"],
"transactionTenderDates": [
{ "tenderId": "CASH-NOK", "dateValue": "2026-09-30", "amount": 630, "quantity": 4 }
]
}

The example is till 1 from How the expected amount is built: 1 630 expected, 1 620 counted. The two quantities measure different things. expectedQuantity counts tender lines in the drawer, where the deposit to the safe counts as −1, so 4 sales and returns less 1 deposit give 3. transactionTenderDates.quantity counts the transactions on each date: 4.

Format: Reconciliation completed and rejected.

Reconciliation recount​

The till audit as recounted, with each tender's correction against the previous count. In the example the manager found the missing 10:

{
"tenantId": "tenant-1",
"businessUnitId": "store-12",
"correlationId": "0b7d2e94-61c3-4f0e-8a54-3e1f9c7d2a65",
"reconciliationId": "tenant-1-store-12-WORKSTATION-CASH_DRAWER-415",
"recountId": "6d2a9f41-0c8e-4b7a-9e35-1f4b8c2d7e90",
"reconciliationType": "CASH_DRAWER",
"workstationId": "till-1",
"operatorId": null,
"userId": "2a4e6c8b-1d3f-4a5c-8e7b-9c0d1e2f3a4b",
"comment": "10 note found under the drawer tray",
"timestamp": "2026-09-30T19:40:03.112Z",
"businessDate": "2026-09-30",
"tenders": [
{
"tenderId": "CASH-NOK",
"currencyId": "NOK",
"isReadOnly": false,
"expectedAmount": 1630,
"actualAmount": 1630,
"amountCorrection": 10,
"expectedQuantity": 3,
"actualQuantity": null,
"quantityCorrection": null,
"isCashChanger": false
}
],
"items": []
}

Format: Reconciliation recount.

Reconciliation change shift​

The till audit's counts in time order, each a shift, with who counted and the deviation per tender, at the count and within the shift. See Shifts.

Format: Reconciliation change shift.

Reconciliation end of day​

One store and business date: the till audits included, and per tender and item the day's expected, counted and deviation totals with their deltas. comment holds the store manager's explanation when the store was outside its limit.

Format: Reconciliation end of day.

Cash balance​

One message per tenant and business date: per store and currency, the cash expected to remain in the drawers and cash changers at the end of the day. See Closing the day.

Format: Cash balance.

Events used inside Hii Retail​

Reconciliation also publishes reconciliation-created (a till audit started, with its float), transfers (cash loans and deposits) and a warning when a drawer's expected amount crosses its limits. They feed Cash Management and Hii Retail's store applications, and are not offered through External Events.