A common Transportation Management Solutions integration failure starts with a simple assumption: the Transportation Management Solutions can be connected to the ERP through a few REST APIs and the problem is solved.
In production, shipment events arrive asynchronously, carriers use different status codes, warehouse systems update at different times, and ERP transactions often require ordering and validation. This is where Transportation Management Solutions need an integration architecture rather than a collection of API calls.
For developers building enterprise inventory and transportation workflows, the architectural challenge is connecting orders, shipments, carriers, warehouses, inventory, and financial records without creating tightly coupled services.
A practical approach is to treat shipment changes as domain events and allow each downstream system to react according to its responsibility.
Context and Setup
A transportation platform typically sits between several systems:
┌──────────────┐
│ ERP │
└──────┬───────┘
│
Order / Invoice
│
┌──────▼───────┐
│ Integration │
│ Service │
└──────┬───────┘
│
┌────────────┼────────────┐
│ │ │
┌─────▼─────┐ ┌────▼────┐ ┌────▼─────┐
│ TMS │ │Warehouse│ │ Carrier │
└───────────┘ └─────────┘ └──────────┘
The integration layer should normalize external events before they reach business services.
For example, one carrier may send OUT_FOR_DELIVERY, another may send OFD, and an internal warehouse system may call the same state DISPATCHED.
A canonical internal event avoids spreading carrier-specific logic throughout the application.
This matters as shipment volume grows. The 2024 Stack Overflow Developer Survey reported that PostgreSQL was used by 48.7% of all respondents, making it the most popular database in the survey's database category. PostgreSQL is therefore a practical choice for systems that need transactional storage alongside integration workloads, although database selection should still follow workload requirements.
Designing Transportation Management Solutions Around Events
Step 1: Define a Canonical Shipment Model
The first step is to establish a common representation of shipment state.
The model should contain only information that downstream services actually need:
{
"shipmentId": "SHP-10482",
"orderId": "ORD-7821",
"carrier": "carrier-a",
"status": "OUT_FOR_DELIVERY",
"eventTime": "2026-09-07T08:30:00Z"
}
The important design decision is separating the external carrier status from the internal business status.
This allows the adapter for each carrier to translate its API into the same domain model.
Instead of:
Carrier A → ERP
Carrier B → ERP
Carrier C → ERP
use:
Carrier A ─┐
Carrier B ─┼→ Normalized Event → Business Services
Carrier C ─┘
That reduces coupling and makes adding another carrier less disruptive.
Step 2: Publish Shipment Events
Once an event is normalized, publish it to a message broker such as Kafka, RabbitMQ, or a cloud-native queue.
A simplified Node.js example might look like this:
async function handleCarrierUpdate(payload) {
// Why: convert carrier-specific statuses before business processing.
const event = normalizeCarrierEvent(payload);
// Why: publishing asynchronously prevents carrier callbacks
// from waiting for every downstream ERP operation.
await eventBus.publish("shipment.status.changed", event);
return { accepted: true };
}
The consumer can then update the relevant systems independently:
async function processShipmentEvent(event) {
// Why: idempotency prevents duplicate carrier callbacks
// from creating duplicate ERP transactions.
if (await eventStore.exists(event.eventId)) return;
await eventStore.save(event.eventId);
// Update transportation state.
await shipmentService.updateStatus(event);
// Notify ERP only when the business state requires it.
if (event.status === "DELIVERED") {
await erpService.recordDelivery(event);
}
}
The eventId is important. Carrier APIs can retry callbacks, and network failures can make the same event appear more than once.
Idempotency turns repeated delivery into a manageable condition instead of a duplicate-order or duplicate-invoice problem.
Step 3: Decide Where Orchestration Belongs
Not every workflow should be event-driven.
Use synchronous APIs when a caller needs an immediate response, such as checking whether a shipment can be created.
Use asynchronous events when processing can happen independently, such as:
- Delivery status updates
- Carrier tracking events
- Warehouse notifications
- Freight reconciliation
- Customer notifications
- Analytics pipelines
The trade-off is complexity. An event-driven architecture improves isolation and retry handling, but it also introduces eventual consistency, message ordering concerns, monitoring requirements, and dead-letter handling.
The correct architecture depends on business criticality, not technology preference.
Real-World Application
In one of our logistics-related implementations at Oodles, the client operated promotional graphics workflows involving up to 41,000 parts per job. The environment included separate systems for quoting, fulfillment, and finance, with Business Central selected as the ERP foundation.
The technical challenge was not simply creating another operational application. The solution needed to connect fulfillment workflows with ERP processes while preserving system responsibilities.
The approach centered on Business Central as the ERP foundation and defined integration boundaries between operational workflows and financial processes.
The measurable scale requirement was significant: kit planning could involve 41,000 parts for a single job. That made data synchronization, process ownership, and transaction design important architectural considerations.
The broader lesson applies directly to Transportation Management Solutions: integration should be designed around business entities and events rather than individual screens or vendor APIs.
You can explore more about Oodles and its engineering capabilities separately from the architecture itself.
Conclusion: Key Takeaways
- Normalize carrier events before sending transportation data into ERP or business services.
- Use idempotency keys for shipment callbacks because external systems can retry events.
- Keep carrier-specific status mapping inside integration adapters rather than business logic.
- Use synchronous APIs for immediate decisions and asynchronous events for independent workflows.
- Treat ERP integration as part of the domain architecture, not as a final connector project.
What are Transportation Management Solutions?
Transportation Management Solutions are software systems that coordinate shipment planning, execution, tracking, carrier interactions, and transportation analytics. In enterprise environments, they commonly integrate with ERP, warehouse, order management, carrier, and inventory systems.
Should a Transportation Management Solutions use REST APIs or event-driven integration?
Most enterprise transportation platforms benefit from using both. REST APIs are appropriate when an immediate response is required, while event-driven messaging works well for shipment updates, tracking events, notifications, and asynchronous ERP processing.
How should duplicate shipment events be handled?
Duplicate events should be handled through idempotent consumers. Each external event should have a unique identifier, which is stored after successful processing. If the same identifier arrives again, the consumer can safely ignore it.
Why normalize carrier status codes?
Carrier normalization prevents vendor-specific status values from spreading through the application. An integration adapter can convert different external values into a canonical domain state, allowing internal services to process transportation events consistently.
Can Transportation Management Solutions work with existing ERP systems?
Yes. Transportation Management Solutions can integrate with existing ERP platforms through APIs, middleware, message queues, database interfaces, or scheduled synchronization. The preferred method depends on ERP capabilities, transaction requirements, data ownership, and integration latency.
Top comments (0)