Skip to main content

Events

Stock Corrections publishes one event. Every accepted call produces one message — there is no batching and no summary event. A retried call publishes the same message again, with the same stockCorrectionId.

scr.public.event.stock-correction.v1

⚠ Subscribe by that topic name. The published JSON schema is filed under a slightly different, plural name — scr.public.event.stock-corrections.v1 — because the schema file and the topic were named separately. The schema describes this event correctly; only the file name differs. Use the topic name above when you set up a subscription, and do not go looking for a plural topic.

The payload​

{
"stockCorrectionId": "5f1c0c4e-6b9e-4c3a-9f2d-1b6d2e8a7c11",
"tenantId": "acme",
"businessUnitId": "store-42",
"itemId": "7350053850019",
"quantity": -3,
"reasonCode": "DMG",
"userId": "a5f460606be52a0b91f57c4b2e5c037d9c2014bb2a9d1566bb87fb3c28ef5de3",
"transactionDateTime": "2026-09-23T07:14:02.000Z",
"comment": "crushed in the stockroom",
"serialNumber": "SN-99481",
"batchNumber": "B-2026-14",
"businessPartnerId": "supplier-4471"
}
FieldAlways presentMeaning
stockCorrectionIdyesIdentifies this correction. The deduplication key — a retried request carries the same one.
tenantIdyesThe tenant
businessUnitIdyesThe store the stock belongs to
itemIdyesThe item corrected
quantityyesThe signed change, not a level. See below.
reasonCodeyesThe configured code the operator chose — see Reason codes
userIdyesOpaque identifier of the caller. Not a name; carries no personal data.
transactionDateTimeyesWhen the correction happened, in UTC. See below.
commentnoFree text, present only if one was given
serialNumbernoPresent for serial-tracked corrections
batchNumbernoPresent for batch-tracked corrections
businessPartnerIdnoPresent when the correction relates to a business partner
stockTypenoReturned when the correction applies to returned stock. Absent means sellable stock.

🛑 quantity is a delta​

The event tells you how much the stock changed by, never what it now is. -3 means three fewer than before it. To hold a running quantity you must add each correction to the balance you already have; a consumer that overwrites its quantity with this field will destroy it.

Nothing on the event tells you the resulting level, and Stock Corrections does not know it.

transactionDateTime is when the correction happened​

The caller may supply it, and the Inventory app always does: it sends the moment the staff member made the correction, even when the handset was offline and the correction reaches the service hours later. A caller that supplies no time gets the moment the service received the call. Either way the value is normalised to UTC.

What this means in practice:

  • Use it for ordering. It does not change across redeliveries, replays or retried calls, which is what ordering needs.
  • Expect it to be in the past, sometimes well in the past. A correction captured in a stockroom with no signal at 09:00 can be published at 11:30 carrying 09:00. For most stock arithmetic that does not matter — the correction is a delta and applies whenever it arrives — but it means corrections arrive out of sequence with other stock movements.
  • Do not assume it is exact for every caller. It is only the real time of the correction when the caller supplied one. For reconstructing a stock position at a past moment, or attributing shrinkage to a shift, treat it as the time of the correction, not the second the stock left the shelf.

Message attributes​

Usable as subscription filters without opening the payload:

AttributeValue
Tenant-Idthe tenant
Business-Unit-Idthe store
Correlation-Idtraces back to the API call that caused the correction
Stock-Correction-Idthe same id as in the payload

Messages also carry B3 trace headers for distributed tracing. Ignore them unless you are participating in the trace.

Consuming these events​

Delivery is at-least-once — expect duplicates. Deduplicate on stockCorrectionId. One correction has one id for its lifetime, and a message carrying an id you have already applied is the same correction, never a second one. Duplicates come from two places: Pub/Sub redelivering a message, and a caller retrying a request, which the service publishes again with the same id and content. Because the quantity is a delta, a duplicate you fail to catch is applied twice and the stock is wrong — this is the one thing worth getting right before you go live.

Do not rely on arrival order. Order by transactionDateTime. Corrections are independent of one another, so ordering rarely changes the outcome of the arithmetic — but if you are building a ledger or a timeline, sort by the event's own timestamp rather than by when you received it.

Corrections are never amended or withdrawn. There is no update event and no delete event. A mistake is undone by a further correction in the opposite direction, which arrives as an ordinary event with its own id. Do not wait for a confirmation that will not come, and do not treat an offsetting correction as a retraction of the first — both are real, and both belong in an audit trail.

Handle unrecognised values. reasonCode is configured per tenant, not drawn from a fixed list, so you will see codes you have never seen before whenever a customer adds one. Pass them through; never reject a correction because its reason is unfamiliar.

New optional fields arrive on this version. Adding an optional field is not a breaking change, so it is added to v1 rather than published as a new version, and the published schema gains the field before any event carries it. Ignore fields you do not recognise, and if you validate against the schema, use the current published copy rather than one you saved. A new version is published only for a breaking change — a field removed, renamed, retyped or made required.

One consumer per business unit applies the correction. The event is broadcast, not addressed. If both Stock Transaction Processing and your own system act on corrections for the same store, the stock moves twice. See Who applies the correction to stock.

What Stock Transaction Processing does with it​

Relevant when Hii Retail is the stock master for the business unit, and worth knowing even when it is not, because it is what the figures in Hii Retail will show.

Stock affectedSellable stock, or returned stock when stockType is Returned
Operation typeSTOCK_CORRECTION
Document typeStockCorrection
Document idthe stockCorrectionId
SourceSCR
Quantityapplied exactly as published, sign included
Duplicatesapplied once per stockCorrectionId; a repeated message is ignored

🛑 The stock type decides where a correction lands; the reason code does not. A correction with no stockType moves sellable stock, whatever its reason. A reason code of Damaged does not move the stock into a damaged or quarantined bucket — it removes it from the quantity the correction names. The reason is recorded for reporting; it does not route the stock anywhere. If you need damaged goods held as a separate balance rather than written off, that is not what this service does.

The correction is also costed. Stock Transaction Processing attaches its own value based on the item's cost, so an accounting consumer should take the value from one source only — see cost calculations.

⚠ Stock Transaction Processing may be configured to ignore corrections entirely. Its tenant-level Do enable PosLog processing switch gates every ingress from Hii Retail services. With it off, this event is published exactly as described and STP simply does not act on it.

Subscribing from outside Hii Retail​

Systems outside the platform do not read the topic directly. Stock corrections are published through Hii Retail's External Events, which is the supported route for external subscribers, listed there as SCR: Stock Corrections with its schema.

Everything on this page applies unchanged to that route — the same payload, the same attributes, the same at-least-once delivery, and the same need to deduplicate on stockCorrectionId.