Skip to content
All case studies
Logistics & e-commerce fulfilment2024 — 2025

Reconciling declared and received inventory across Salesforce and a WMS

A bidirectional integration that detects, quantifies, and displays the difference between what a merchant declared they would ship and what the warehouse physically received.

Context
A logistics and e-commerce fulfilment provider
Role
Salesforce Developer — owned the Salesforce side end to end
Period
2024 — 2025
Systems
Salesforce ⇄ AWS Lambda / SQS ⇄ Warehouse Management System

At a glance

The business gained a systematic answer to a question it previously answered by hand, or not at all.

  • Expected versus actual received is compared automatically on every receiving order.
  • Discrepancies are visible per item, with direction and magnitude, rather than inferred later.
  • Salesforce reflects what physically arrived, so downstream inventory decisions use accurate data.
01

Overview

What this was

A merchant declares an incoming shipment; the warehouse physically receives it. Those two rarely match — short shipments, overages, and wrong SKUs are routine. This project made Salesforce the system of record for warehouse receiving, integrated it bidirectionally with the warehouse management system through an AWS pipeline, and surfaced the per-item discrepancy to the people who needed to act on it.


Business context

A logistics services company operating warehouse and fulfilment operations for merchants. Salesforce carried order management; the warehouse ran on a separate management system with its own scanning tool. Receiving accuracy directly affects inventory accuracy, and inventory accuracy affects everything downstream — what can be sold, what gets promised to a customer, and what a merchant is billed for.

Delivery timeline

  1. 01

    Discovery

    Traced the receiving process and where expected and actual diverge.

  2. 02

    Data model

    Designed the WRO header, expected items, and actual received items.

  3. 03

    Integration surface

    Built the inbound Apex REST endpoints and the outbound flow.

  4. 04

    Pipeline

    Designed the AWS capture/consume functions in both directions.

  5. 05

    Reconciliation

    Per-item discrepancy calculation triggered on receipt completion.

  6. 06

    User experience

    LWC presenting expected, actual, and variance side by side.

02

Business problem

Did the warehouse actually receive what the merchant said they would send? Nobody could answer that without opening two systems and comparing by hand.

No automated reconciliation

Expected versus actual received was never systematically compared.

Discrepancies stayed invisible

Over- and under-deliveries went unnoticed until they caused a downstream problem.

Inventory drifted from reality

Salesforce did not reflect what had physically arrived at the warehouse.

No view for users

No single place showed whether — and where — a receiving order was short or over.

03

Challenges

What made this harder than it looks

  1. 01

    A direct callout would couple Salesforce to the warehouse system

    If the warehouse system were unavailable, requests made straight from Apex would simply be lost, and the user or transaction would be blocked waiting on a system outside our control.

  2. 02

    Volume exceeded what synchronous processing could carry

    A single receiving order can carry a long list of items. Pushing each as its own synchronous callout runs into platform limits well before it runs into business volume.

  3. 03

    Responses had to find their way back into Salesforce

    The actual received items originate in the warehouse system. Getting them back into Salesforce reliably is a second integration problem, not a detail of the first.

  4. 04

    The trigger point sat in the other system

    Salesforce cannot know when physical receiving has finished. That signal belongs to the warehouse users, so the design had to treat an external status update as the start of a process rather than the end of one.

  5. 05

    Discrepancy had to be per item, not per order

    "This order is short" is not actionable. "This SKU is short by four units" is. The data model had to support item-level comparison rather than an order-level flag.

04

Architecture

How the system fits together

Salesforce is the system of record. AWS is the integration pipeline. A capture-then-consume model decouples the two systems in both directions, so neither one blocks or loses work when the other is unavailable.

SALESFORCESystem of recordINTEGRATION LAYERBoundary & transportEXTERNAL SYSTEMSOutside our controlApex RESTInbound endpointsWRO + itemsExpected / actual / varianceReconciliation LWCPer-item viewCaptureLambda — receives DTOsQueueSQS — absorbs burstsConsumeLambda — pushes onwardWarehouse systemReceives the orderWarehouse toolScan + mark completeShopifyMerchant storefrontorders & stockcreateDTO listcreate orderstatus = Completedrequest actual itemsactual itemspost backreconcile
SynchronousAsynchronous, queued, or scheduled
  1. Shopify to Apex REST: orders & stock (asynchronous, queued, or scheduled)
  2. Apex REST to WRO + items: create
  3. WRO + items to Capture: DTO list
  4. Capture to Queue (asynchronous, queued, or scheduled)
  5. Queue to Consume (asynchronous, queued, or scheduled)
  6. Consume to Warehouse system: create order
  7. Warehouse system to Warehouse tool
  8. Warehouse tool to Apex REST: status = Completed
  9. WRO + items to Capture: request actual items
  10. Warehouse system to Consume: actual items (asynchronous, queued, or scheduled)
  11. Consume to Apex REST: post back (asynchronous, queued, or scheduled)
  12. WRO + items to Reconciliation LWC: reconcile

End-to-end flow

  1. 01

    Create the receiving order

    An external system calls a Salesforce Apex REST endpoint, creating the WRO record together with its list of expected items.

  2. 02

    Push to the warehouse

    Salesforce sends the order out through the AWS pipeline to be created in the warehouse management system.

  3. 03

    Physical receiving

    Warehouse users scan the items in the warehouse tool and mark receiving complete.

  4. 04

    Status becomes Completed

    The warehouse system updates the Salesforce record to Completed. This is the trigger point for everything that follows.

  5. 05

    Fetch the actual items

    That status change triggers an outbound request to retrieve the items the warehouse actually received.

  6. 06

    Reconcile and display

    Once the actual items are in Salesforce, reconciliation runs and an LWC shows expected against actual, with the discrepancy per item.

Technologies

Salesforce

  • Apex REST (inbound endpoints)
  • Apex callouts (outbound)
  • Custom objects — WRO header, expected items, actual items
  • Custom Metadata (endpoint configuration)
  • Record-triggered automation
  • Lightning Web Components
  • DTOs and JSON parsing

AWS

  • Lambda — capture function
  • Lambda — consume function
  • SQS queueing

External

  • Warehouse management system API
  • Warehouse scanning tool
  • Shopify
05

Solution design

The choices that shaped everything else

Expected and actual are separate records, not two fields

Warehouse_Receiving_Order_Item__c holds what was declared. Actual_WRO_Item__c holds what arrived, with its own quantity and a signed discrepancy. Modelling them separately means an item present in one and absent from the other is representable — which is exactly the case a two-field design cannot express.

A signed discrepancy, not a boolean

The variance carries direction and magnitude. Short by four and over by four are different operational problems and are stored as different values, so both the UI and future reporting can distinguish them.

DTOs sit between the API contract and the schema

Inbound and outbound payloads are parsed into explicit data transfer objects rather than deserialised straight onto SObjects. The external contract can then change without forcing a schema change, and a malformed payload fails at a boundary that can report why.

The external status update is the trigger

Setting status to Completed from the warehouse is what initiates the retrieval of actual items. Salesforce does not poll and does not guess when receiving finished — it reacts to the system that knows.

The view answers the question directly

The LWC places expected, actual, and discrepancy side by side per item. The user is not asked to compare two lists themselves; the comparison is the interface.

06

Technical decisions

What was decided, why, and what it cost

Every decision below is paired with its trade-off. A design choice without a stated cost usually means the cost was not examined.

01

Split the pipeline into capture and consume functions

Rationale

Capture accepts the list of DTOs from Salesforce and returns immediately. Consume pushes them onward to the external system. The same pair works in reverse for responses coming back. Salesforce is therefore never blocked on the warehouse system, requests survive an outage instead of being lost, and queued DTOs absorb volume.

Trade-off

Two functions and a queue are more moving parts than one callout, and the flow becomes eventually consistent rather than immediate. Accepted because losing a receiving request is materially worse than showing it a few seconds late.

02

Hold the pipeline endpoints in Custom Metadata

Rationale

Endpoint URLs change between sandbox, staging, and production, and again whenever infrastructure moves. As metadata they are configuration; in Apex they would be a deployment.

Trade-off

One indirection between reading the code and knowing the target URL. Worth it to keep environment differences out of source control.

03

Make Salesforce the system of record for receiving

Rationale

Reconciliation, reporting, and the user-facing view all need one authoritative copy. Splitting that across two systems would recreate the original problem one layer up.

Trade-off

Salesforce carries the storage and the write volume for item-level data it does not originate.

04

Reconcile after receipt rather than incrementally during it

Rationale

A partially scanned order is legitimately incomplete. Comparing before the warehouse declares itself finished would generate discrepancies that are not discrepancies.

Trade-off

No live progress view during receiving. The business question is asked after receipt, so this matches how the information is actually used.

07

My responsibilities

What I personally owned

  • Designed the data model — receiving order, expected items, actual received items, and their relationships.
  • Built the Apex REST endpoints for inbound order creation and for receiving actual items.
  • Configured the outbound callout to the AWS pipeline, with the endpoint held in Custom Metadata.
  • Designed the capture/consume pipeline shape and the contract at each hop.
  • Implemented the per-item reconciliation logic that computes the discrepancy.
  • Built the automation that turns an external status change into a retrieval request.
  • Built the Lightning Web Component presenting expected, actual, and discrepancy together.
08

Implementation process

How it was actually built

  1. 01

    Started from the operational question

    The requirement was not "integrate with the WMS" but "let users know if there is a discrepancy, and what it is". That framing determined the data model and the interface, and it is why the deliverable is a comparison view rather than a sync job.

  2. 02

    Modelled the data before designing the integration

    Getting expected and actual into separate objects with a signed variance made the reconciliation logic almost trivial. Most of the design effort went here, which is where it belonged.

  3. 03

    Built the inbound surface first

    With the Apex REST endpoints in place and testable against real payloads, the pipeline could be developed against a known contract instead of against an assumption.

  4. 04

    Designed the pipeline for the outage case

    The capture/consume split exists because the interesting scenario is the warehouse system being unavailable. Designing for that first is what made the happy path straightforward.

  5. 05

    Closed the loop on the trigger

    Wiring status = Completed to the retrieval request turned two independent integrations into one coherent process with a clear start and end.

09

Security considerations

What was protected, and how

Inbound endpoints are authenticated, not open

The Apex REST surface is reached by a named integration user with a permission set scoped to exactly the objects and fields the integration touches — not by an administrator profile.

No credentials or endpoints in source

Endpoint configuration lives in Custom Metadata and authentication through the platform credential store, so nothing sensitive is committed to version control.

Payloads are validated at the boundary

Explicit DTO parsing rejects malformed input before it reaches the data model, rather than partially writing records and failing midway.

The integration user is least-privilege

Object and field permissions are granted through a dedicated permission set, so the integration cannot read or modify data outside its scope.

11

Business value

The business gained a systematic answer to a question it previously answered by hand, or not at all.

  • Expected versus actual received is compared automatically on every receiving order.
  • Discrepancies are visible per item, with direction and magnitude, rather than inferred later.
  • Salesforce reflects what physically arrived, so downstream inventory decisions use accurate data.
  • Receiving work continues to be captured when the warehouse system is unavailable.
  • Automated logistics and fulfilment workflows, reducing repetitive manual processing and improving operational reliability.
12

Lessons learned

What I took from it

The data model was the real design work

Separating expected from actual and storing a signed variance removed nearly all of the apparent complexity. What looked like an integration problem was mostly a modelling problem.

Decoupling is worth its extra parts

The capture/consume pipeline added infrastructure, but it converted an entire class of failure — the other system being down — from lost work into delayed work.

Configuration in metadata pays for itself immediately

Endpoints changed during delivery. Because they were metadata, each change was a configuration edit rather than a deployment cycle.

A per-record view answers today; reporting answers tomorrow

The LWC solved the immediate question well and revealed the next one: nobody could see discrepancy patterns across orders. Solving one question clearly is what makes the next one visible.

13

Future improvements

What I would do next

Listing the known gaps is part of the handover. A system described as finished usually means nobody looked hard enough.

  1. A discrepancy dashboard across receiving orders

    The LWC shows the discrepancy for a single order. Reporting and a dashboard across all receiving orders would let the business see trends by warehouse, merchant, product, or period — and act on recurring causes rather than individual cases. This is the single most valuable addition.

    Improvement 1
  2. Automated alerting on threshold breach

    A discrepancy above a configurable tolerance should notify a person rather than wait to be noticed, with the threshold held as metadata alongside the endpoint configuration.

    Improvement 2
  3. Reconciliation history rather than current state

    Retaining each reconciliation run would allow a receiving order to be audited over time, including re-counts and corrections.

    Improvement 3