Events API Overview
Introduction
The Wholechain Events API is used to record the movement, creation, transformation, adjustment, and removal of products throughout a supply chain.
Unlike APIs where each record can be created independently, Wholechain events form a chronological chain.
Each event affects the product's current state and determines what events can happen next.
A typical product journey may look like:
Receive
↓
Transform
↓
Ship
↓
Receive
↓
Ship
Or:
Commission
↓
Observe
↓
Transform
↓
Ship
This means that when submitting an event, Wholechain does not only validate the payload itself. It also validates whether the event makes sense based on the events and inventory that already exist before that point in time.
Events Are Connected
Events represent what happens to a specific:
- Product
- Lot or serial
- Quantity
- Location
- Trade partner
- Point in time
These values allow Wholechain to connect one event to another and build the product's traceability history.
For example:
Receive
Product: Salmon
Lot: LOT-001
Location: Warehouse A
Quantity: 100 kg
Time: 09:00
↓
Transform
Input Product: Salmon
Input Lot: LOT-001
Location: Warehouse A
Quantity: 100 kg
Time: 11:00
↓
Ship
Output Product: Salmon Fillet
Lot: LOT-002
Location: Warehouse A
Quantity: 80 kg
Time: 15:00
The Transform works because Wholechain can find LOT-001 at Warehouse A before 11:00.
The Ship works because the output of the Transform exists before 15:00.
Event Timing Matters
The event timestamp determines where an event sits within the supply chain history.
Events must therefore occur in the correct chronological order.
For example:
09:00 Receive 100 kg
↓
11:00 Transform 100 kg
↓
15:00 Ship 80 kg
This is valid because each event happens after the event that makes the required inventory available.
The following would not be valid:
11:00 Transform 100 kg
↓
12:00 Receive 100 kg
At 11:00, the Receive has not happened yet.
Therefore, as far as Wholechain is concerned, the inventory required for the Transform does not yet exist.
It does not matter if the Receive request was sent to the API first. The event timestamp determines the sequence of events, not simply the order in which the API requests are submitted.
Avoid Using the Same Time for Dependent Events
Events that depend on each other should have clearly ordered timestamps.
For example:
10:00:00 Ship from Supplier
10:05:00 Receive at Processor
is preferable to:
10:00:00 Ship from Supplier
10:00:00 Receive at Processor
If two dependent events occur at exactly the same time, Wholechain will not have a clear preceding event to connect against.
If the Receive depends on the Ship, the Ship should occur before the Receive.
Likewise:
Receive → Transform → Ship
should mean:
Receive Time < Transform Time < Ship Time
Correct timestamps are therefore essential for both inventory validation and traceability.
Inventory Must Exist Before It Can Be Used
Many Wholechain events operate on existing inventory.
You cannot simply create a Transform, Ship, Observe, or Decommission event for any product and lot combination.
Wholechain must first be able to find the relevant inventory.
For example:
Receive
100 kg of LOT-001
↓
Available Inventory
100 kg of LOT-001
↓
Transform
Consumes 60 kg
↓
Available Inventory
40 kg of LOT-001
The Transform succeeds because 100 kg was available before the event.
If you attempted to Transform 120 kg:
Available: 100 kg
Requested: 120 kg
the event cannot be completed because there is insufficient inventory.
Inventory Is Identified by More Than Just the Lot
When Wholechain searches for inventory, the lot number alone is not enough.
The relevant product instance generally needs to match the event's:
Product
+
Lot / Serial
+
Location
+
Event Time
Therefore, inventory may exist in Wholechain but still not be available for a particular event.
For example:
Product: Salmon
Lot: LOT-001
Location: Warehouse A
Quantity: 100 kg
A Ship requesting:
Product: Salmon
Lot: LOT-001
Location: Warehouse B
cannot use that inventory.
The inventory exists, but it exists at the wrong location.
The same applies when the Product ID, lot code, or event timing does not match.
Events Change Available Inventory
Every inventory-related event affects what can happen next.
For example:
Receive 100 kg
↓
Inventory = 100 kg
Ship 30 kg
↓
Inventory = 70 kg
Transform 50 kg
↓
Inventory = 20 kg
Decommission 10 kg
↓
Inventory = 10 kg
Future events can only operate on the remaining available inventory.
This is why events should be thought of as a continuous product history, rather than separate API transactions.
Creating Inventory
Before inventory can be consumed, it generally needs to enter Wholechain.
Two common events used to establish inventory are:
Receive
A Receive event records product arriving at a location.
For example:
Supplier
↓
Receive
↓
Warehouse A
LOT-001
100 kg
Once received, that inventory becomes available at the receiving location for subsequent events.
A Receive may also connect to an upstream Ship where the corresponding shipment exists.
Commission
A Commission event creates inventory directly at a location.
This is useful where inventory originates within the organization and there is no preceding external Receive that establishes the product.
For example:
Commission
↓
LOT-001
100 kg
Warehouse A
Once commissioned, the lot can be used by subsequent inventory events.
Transform
A Transform represents the conversion of one or more existing product lots into one or more output lots.
For example:
INPUT
Whole Salmon
LOT-001
100 kg
↓
TRANSFORM
↓
OUTPUT
Salmon Fillet
LOT-002
60 kg
Salmon Trim
LOT-003
30 kg
The important point is that the input inventory must already exist before the Transform event occurs.
Wholechain needs to find:
Input Product
Input Lot
Input Location
Required Quantity
Inventory available before the Transform time
You therefore cannot create a valid Transform merely because the payload contains an input lot.
If that input inventory does not exist at that location and time, the Transform cannot correctly consume it.
Once the Transform is completed, the output lots become available inventory for later events.
Receive LOT-001
↓
Transform LOT-001 → LOT-002
↓
Ship LOT-002
Ship
A Ship event moves inventory out of a location.
For example:
Warehouse A
LOT-001
100 kg
↓ Ship 40 kg
Customer
Remaining at Warehouse A:
60 kg
Wholechain therefore needs to find the inventory at the shipping location before the Ship event occurs.
The following must match the available inventory:
- Product
- Lot
- Shipping location
- Quantity
- Event time
A Ship event normally reduces the available quantity at the origin location.
Direct Ship
Ship events can support a DirectShip option.
This provides an exception to the normal inventory requirement.
DirectShip: false
Wholechain expects the inventory to exist.
If the requested inventory cannot be found, the shipment will not be completed normally.
DirectShip: true
If Wholechain cannot find the expected inventory, the shipment can still be recorded.
This is useful when there is an earlier data issue in the supply chain—for example, an upstream event was never successfully transmitted—but you still need to record the shipment to the customer.
Earlier inventory data missing
↓
DirectShip = true
↓
Shipment can still be recorded
Direct Ship should therefore be treated as a fallback mechanism. It does not mean that inventory validation is generally unnecessary.
Receive After a Ship
When representing movement between locations, the logical sequence is:
Location A
↓
Ship
↓
Receive
↓
Location B
For example:
09:00
Ship LOT-001
Warehouse A → Warehouse B
↓
12:00
Receive LOT-001
at Warehouse B
Once the Receive occurs, the inventory becomes available at Warehouse B.
Events after that Receive should reference Warehouse B.
For example:
Warehouse A
↓
Ship
↓
Warehouse B
↓
Receive
↓
Transform
↓
Ship
You should not attempt to Transform the product at Warehouse B before the Receive establishes it there.
Observe
An Observe event records an adjustment or observation against existing inventory.
For example:
Current Inventory
100 kg
↓
Observe
5 kg
↓
New Inventory
5 kg
An Observe event therefore normally needs an existing product instance to act against.
The product, lot, location, and timing must correspond to inventory that exists before the Observe event.
An Observe does not move the product to another location and quantity must be greater than 0.
Decommission
A Decommission event removes some or all of a product from the active supply chain.
For example:
Inventory
100 kg
↓
Decommission
20 kg
↓
Available Inventory
80 kg
Common examples include:
- Spoilage
- Damage
- Expiration
- Rejection
- Product loss
- Product being taken permanently out of circulation
The quantity being decommissioned must be available before the Decommission occurs.
Once inventory has been decommissioned, that quantity cannot subsequently be shipped or transformed.
Aggregate and Disaggregate
Aggregate and Disaggregate events describe relationships between products and containers or grouped units.
Conceptually:
Individual Products
↓
Aggregate
↓
Container / Parent Unit
and:
Container / Parent Unit
↓
Disaggregate
↓
Individual Products
As with other events, the products or units referenced by these events need to exist at the appropriate location and point in the event chain.
Events Cannot Be Treated as Independent Records
Consider the following:
1. Receive 100 kg
2. Transform 60 kg
3. Ship 40 kg
These are not three unrelated records.
They represent changes to the same inventory over time.
Receive
Inventory +100
↓
Transform
Inventory -60
↓
Ship
Inventory -40
Wholechain therefore continuously evaluates what inventory should exist at each point in the chain.
This is why an event can have a structurally correct JSON payload but still fail business validation.
Inserting Events Into an Existing Chain
Extra care is required when adding or correcting historical events.
For example, assume Wholechain already contains:
September 1
Receive 100 kg
September 4
Ship 50 kg
You should not assume that you can later insert any inventory-consuming event between those two events without affecting the events that follow.
The chain is already dependent on the inventory history.
For example:
Sep 1
Receive 100 kg
↓
Sep 3
NEW Transform 80 kg
↓
Sep 4
Existing Ship 50 kg
The existing Ship may no longer be valid because the Transform has changed the inventory that should be available to it.
Historical corrections may therefore require later dependent events to be corrected, removed, or reposted in the correct sequence.
Think of the chain as:
Event 1
↓
determines state for
↓
Event 2
↓
determines state for
↓
Event 3
Changing Event 1 or Event 2 can affect everything downstream.
Updating Events
Where an existing event is being updated, use the same event identifier according to the relevant event endpoint's update behavior.
The event ID is important because it tells Wholechain that the request relates to an existing event rather than representing an entirely separate business event.
For example:
EVENT-001
Receive 50 kg
may later be updated as:
EVENT-001
Receive 100 kg
rather than creating:
EVENT-001
50 kg
EVENT-002
100 kg
when the business system is actually sending an updated version of the same transaction.
Updating an earlier event can also affect downstream inventory, so updates should always be considered in the context of the entire event chain.
Common Reasons an Event Cannot Find Inventory
If Wholechain reports that a product instance or inventory cannot be found, check the complete chain rather than only the failing event.
Common causes include:
-
Incorrect Event Time
The event occurs before the event that created or received the inventory.
-
Incorrect Location
The lot exists, but at another location.
-
Incorrect Product ID
The lot exists against a different product.
-
Incorrect Lot or Serial
The product exists, but the specified lot does not match.
-
Insufficient Quantity
Some inventory exists, but not enough remains for the requested event.
-
Inventory Was Already Consumed
A previous Transform, Ship, Observe adjustment, or Decommission has reduced or removed the inventory.
-
An Earlier Event Is Missing
The Receive, Commission, Transform, or other event that should have established the inventory was never successfully created.
-
Events Are in the Wrong Chronological Order
The required inventory only becomes available after the event that is trying to use it.
-
Dependent Events Use the Same Timestamp
Wholechain cannot establish the expected preceding inventory relationship correctly.
-
A Historical Event Was Changed
An earlier update may have changed the inventory available to later events.
Example of a Correct Event Chain
Consider a processor receiving fish, processing it, and shipping the finished product.
08:00
RECEIVE
Product: Whole Salmon
Lot: RAW-001
Location: Processing Plant
Quantity: 100 kg
↓
10:00
TRANSFORM
Input:
Whole Salmon
RAW-001
100 kg
Outputs:
Salmon Fillet
FILLET-001
70 kg
Salmon Trim
TRIM-001
20 kg
↓
14:00
SHIP
Product: Salmon Fillet
Lot: FILLET-001
Location: Processing Plant
Quantity: 50 kg
↓
Remaining Inventory:
FILLET-001 = 20 kg
TRIM-001 = 20 kg
At every stage, the event is possible because the required inventory exists immediately before the event occurs.
Example of an Incorrect Event Chain
08:00
Transform RAW-001
↓
10:00
Receive RAW-001
The Transform cannot correctly use the lot because the inventory does not exist until 10:00.
Another example:
08:00
Receive
LOT-001
Warehouse A
100 kg
↓
10:00
Ship
LOT-001
Warehouse B
50 kg
This also fails normal inventory logic because the inventory exists at Warehouse A, not Warehouse B.
The Key Rule
When working with the Events API, always ask:
What inventory should exist at this exact location immediately before this event occurs?
If the answer does not match the event you are sending, the event will not form the expected Wholechain traceability chain.
Before submitting an event, confirm:
- Is the Product ID correct?
- Is the Lot or Serial correct?
- Is the Location correct?
- Does sufficient inventory exist?
- Did the previous event happen first?
- Is the event timestamp correct?
- Has any previous event already consumed this inventory?
- Does the quantity make sense?
- Does the event logically follow the preceding supply chain event?
Wholechain events should therefore always be designed and tested as an end-to-end event flow, not as individual API calls.