A customer opens a chat: "Where is my order, and why was I charged more than the cart showed?"
The agent opens the order tab. Then the warehouse system. Then the carrier portal. Then the payment history. Two minutes later they answer, using data that last refreshed the night before.
This looks like a tab problem. It isn't. Five systems describe the same order differently, and nobody has decided which one is right.
The five systems and what each actually knows
Most mid-market ecommerce operations run some version of this stack.
The commerce platform holds order composition, totals, and payment method. It does not reflect a partial refund your finance team issued manually.
The ERP or accounting system holds pricing and inventory. It syncs on a schedule, rarely in real time.
The warehouse system knows what physically shipped. Divergence from the platform is routine: the order shows as picked, but one SKU wasn't on the shelf.
Carrier data knows where the package is. This one deserves its own section.
The CRM or ticketing system holds customer history, and it usually isn't keyed to the order number. The join runs through email, which the customer may have entered differently.
Why carrier status is the worst data source in the stack
There is no universal industry standard for shipment status. Every carrier describes the same journey in its own vocabulary.
What USPS calls "In Transit to Next Facility," UPS calls "On the Way," and DHL calls "Shipment in transit." Same physical event. USPS surfaces delays as a distinct "Arriving Late" status, while UPS and FedEx bundle them under a generic "Exception" and push the actual reason into a sub-code.
The cardinality varies by an order of magnitude. Carriers emit anywhere from 10 to 115 distinct statuses depending on the provider.
There's a second-order effect that lands directly on your support queue. USPS scans less frequently than its competitors, so tracking looks frozen while the package is moving normally. The customer sees two days of silence and opens a chat. Nothing broke. You just absorbed a wave of tickets generated by a scanning cadence.
Collapsing that into one status field an agent can act on is a build in itself, and it's the part teams consistently scope as trivial. The mechanics of normalizing conflicting data sources are worth understanding before you commit to an approach.
The data isn't merely scattered. It conflicts. One order, five versions of the truth, and none of the systems considers itself wrong.
Why the obvious fixes don't hold
Most teams work through three stages, and each hits a different wall.
Stage one: train the agents. Write a runbook covering what to check and in what order. This survives until the first round of attrition. A new hire takes a month to internalize it, and five tabs are still five tabs. Response time doesn't move.
Stage two: pipe everything into the chat window. Data from every system surfaces next to the conversation. This genuinely helps. The agent stops context-switching.
But surfacing data is not resolving it. The agent now sees that the platform says "shipped" while the warehouse says "picking," and sees it faster than before. Then they call the warehouse anyway.
Stage three: consolidate into one report. Nightly ETL, single table, clean dashboard. This fails on freshness. The customer asks about a status at 2pm; the data was assembled at 3am.
Each approach solves part of the problem. None solves the actual one: no field has an owner.
The integration work is the easy half. The hard part is deciding which system wins when two disagree, and that's an organizational question before it's a technical one. It also determines the shape of what you end up with: building it in-house instead of licensing it, or bolting a sixth tool onto the five you already run.
Three questions that determine the architecture
Answer these before you build or buy anything. It costs nothing and takes one working day with the heads of support, warehouse, and finance in the same room.
One: which source owns each field
Not which system owns the domain. Which source owns the field. These are different questions.
| Field | System of record | Not the source |
|---|---|---|
| Order composition | Commerce platform | Warehouse (only holds shipped items) |
| Actually shipped | Warehouse system | Commerce platform |
| Inventory on hand | Warehouse system | ERP (syncs less often) |
| Amount charged | Payment provider | Order record (misses refunds) |
| Delivery status | Carrier | Internal manager flag |
| Interaction history | Ticketing system | CRM |
One page. It looks trivial and it eliminates most of the recurring argument about whose numbers are correct. It also becomes your integration spec if this turns into a build.
Two: what freshness do you actually need
This is where budgets get burned. "Everything in real time" sounds correct, costs disproportionately, and is almost always unnecessary.
Freshness isn't determined by how important the data feels. It's determined by how fast the value changes and what happens when an agent quotes a stale one.
| Data | Required freshness | Mechanism |
|---|---|---|
| Delivery status | Minutes | Carrier webhook |
| Inventory (low stock) | Minutes | Webhook or tight polling |
| Amount charged | Minutes | Payment provider webhook |
| Purchase history | Daily | Nightly batch |
| Reporting data | Daily | Nightly batch |
Two implementation notes that matter more than the polling-versus-webhooks debate itself.
Rate limits bite earlier than you'd expect. Polling every five minutes across a few thousand active orders will exhaust most vendor API quotas. This constrains the design before latency does.
Webhooks arrive more than once. A network blip means the acknowledgment never lands and the sender retries. Every inbound event needs an idempotency key and a dedupe check on your side. Without it, one partial refund posts three times and inventory drifts negative. This is the failure mode that shows up in week six, not week one.
The gap between "everything real time" and "three fields real time" is a multiple on total cost.
Three: read or write
Displaying data to an agent is one problem. Letting them modify an order from the chat window is a categorically different one.
Write access introduces permissions, audit logging, rollback, and reconciliation against the warehouse. The complexity delta between read and write is consistently underestimated at kickoff and discovered mid-project.
Start read-only. Add write operations individually, scoped by amount and transaction type.
What it looks like assembled
The working shape is a layer between the source systems and the chat window.
It pulls from each source, normalizes into a shared model of order, line item, shipment, payment, and customer, resolves conflicts using the ownership table, and returns one card instead of five tabs.
Three decisions worth making up front.
Store both the normalized status and the raw one. This is how shipment aggregation APIs are structured: they return a normalized status code alongside the carrier's original description. The agent needs the normalized value to triage quickly. The raw value matters when the customer is reading the same tracking page and quoting the exact phrase back at you.
Solve identity resolution deliberately. The platform keys on email, the CRM on phone, the ERP on an internal code. This never reaches 100% coverage. The pragmatic approach is to anchor on the order number as the reliable join key and treat email and phone as secondary signals carrying a confidence score, not as identity.
Set TTL per field, not per system. Delivery status expires in a minute; purchase history in a day. A single cache policy across everything either burns your API quota or serves stale data to an agent mid-conversation.
There's also the failure mode nobody plans for: sources that change without notice. A carrier portal ships a layout update and your scraper stops working silently. Reports keep arriving, just empty. Resilient extraction reads pages semantically rather than binding to fixed DOM structure.
On unstructured sources. A meaningful share of what your agents need arrives as free text: a warehouse comment, a supplier email, a scanned bill of lading. Historically that data simply never reached the agent. Language models now extract structure from it reliably enough to be worth wiring in. This is one of the cases where the technology genuinely changes the unit economics of the problem rather than appearing in the pitch deck.
What to do Monday
Three steps that require no budget approval.
Count the tabs. Sit with an agent for an hour and watch how many systems they open on a typical ticket. Don't ask them, watch. The number usually surprises whoever owns the function.
Write down your five most common questions. Next to each, note where the answer lives and how quickly it goes stale. You'll likely find that two of the five don't need current data at all, and exactly one needs minute-level freshness.
Assign an owner to three contested fields. Inventory, delivery status, amount charged. Just decide which system wins. That's a thirty-minute meeting, and the effect shows up before anyone writes code.
Back to the beginning
The customer asks where the order is and why the charge was higher.
The agent sees one card: order composition, what actually shipped, the carrier status in plain language with the original phrasing beside it, and the charged amount with the partial refund broken out. They answer in twenty seconds.
The customer never learns there were five systems behind that. They don't need to. They need an answer they won't have to verify again tomorrow.

