ERP-to-WMS & 3PL Integration Playbook

Type: ERP Integration Systems: Manhattan Active WM, Blue Yonder WMS, Oracle WMS Cloud, SAP EWM, ShipBob, ShipStation, Flexport Confidence: 0.85 Sources: 8 Verified: 2026-03-03 Freshness: 2026-03-03

TL;DR

System Profile

This integration playbook covers the end-to-end data flow between ERP systems and warehouse management systems (WMS) or third-party logistics (3PL) providers. It addresses both enterprise WMS platforms (Manhattan Active WM, Blue Yonder, Oracle WMS Cloud, SAP EWM) and cloud-based 3PL APIs (ShipBob, ShipStation, Flexport). The playbook applies regardless of which ERP system is the source — SAP S/4HANA, Oracle ERP Cloud, NetSuite, Microsoft Dynamics 365, or others.

SystemRoleAPI SurfaceDirection
ERP (SAP, Oracle, NetSuite, D365)Order master, inventory financial ledger, item masterVaries by ERPOutbound (orders) / Inbound (confirmations)
Manhattan Active WMCloud-native WMS — allocation, pick/pack/shipREST API (OAuth 2.0)Inbound (orders) / Outbound (shipments)
Blue Yonder WMSEnterprise WMS — wave planning, labor mgmtMOCA, REST, EDIInbound (orders) / Outbound (shipments)
Oracle WMS CloudCloud WMS — receiving, putaway, fulfillmentREST API (XML/JSON)Inbound (orders) / Outbound (shipments)
SAP EWMSAP-native WMS — embedded or decentralizedOData, IDoc, RFC/BAPIBidirectional with S/4HANA
ShipBob / ShipStation / Flexport3PL fulfillment APIsREST API (API key)Inbound (orders) / Outbound (tracking)
Middleware (MuleSoft, Boomi, Celigo)Integration orchestratorN/AOrchestrator

API Surfaces & Capabilities

API SurfaceProtocolBest ForAuth MethodReal-time?Bulk?EDI Support
Manhattan Active WM RESTHTTPS/JSONOrder release, inventory queries, shipment confirmationOAuth 2.0 client credentialsYesLimited (pagination)No (separate EDI gateway)
Blue Yonder MOCAProprietary TCPDirect WMS operations, wave managementSession-basedYesYesN/A
Blue Yonder Integration APIHTTPS/JSONModern integrations, event-drivenAPI gateway tokenYesYesVia SPS Commerce
Oracle WMS Cloud RESTHTTPS/XML+JSONInbound/outbound shipments, inventoryOAuth 2.0YesVia file importVia Oracle Integration Cloud
SAP EWM IDocRFC/ALEHigh-volume batch order/confirmation exchangeSAP system authNear-real-timeYesVia SAP PI/PO
SAP EWM ODataHTTPS/JSONModern real-time queries, mobile appsOAuth 2.0 / SAMLYesLimitedNo
ShipBob REST APIHTTPS/JSONOrder creation, tracking, inventory levelsAPI keyYesPagination (250/page)No
ShipStation REST APIHTTPS/JSONOrder import, label generation, shipment trackingAPI key (Basic auth)YesPagination (500/page)No
Flexport REST APIHTTPS/JSONFreight shipments, tracking milestones, documentsAPI key (Bearer)YesPaginationNo
EDI 940/945/856AS2, SFTP, VANTraditional WMS without API, large retailersVAN certificateNo (batch)YesNative

Rate Limits & Quotas

Per-Request Limits

Limit TypeValueApplies ToNotes
Max records per page250ShipBob APIUse cursor-based pagination for full result sets
Max records per page500ShipStation APIOffset/limit pagination
Max request body size50 MBOracle WMS Cloud RESTSplit larger XML payloads
Max IDoc batch size10,000 IDocsSAP EWM (via PI/PO)Larger batches cause qRFC queue congestion
Max concurrent REST calls5 per clientManhattan Active WMQueued beyond limit; 429 after 30s queue timeout

Rolling / Daily Limits

Limit TypeValueWindowSystem
API calls40 requests/secondPer secondShipStation (sustained)
API callsFair use / throttledRollingManhattan Active WM (per tenant)
Bulk file imports5 concurrent jobsPer tenantOracle WMS Cloud
IDoc throughput~50,000/hourSustainedSAP EWM (depends on sizing)
Webhook deliveries1,000/minutePer merchantShipBob

Authentication

SystemFlowToken LifetimeRefresh?Notes
Manhattan Active WMOAuth 2.0 client credentials1 hourYes (new token request)Requires pre-registered client app
Blue Yonder WMSMOCA session + API gateway tokenSession-based (30 min idle)Re-authenticateStateful — sticky sessions required
Oracle WMS CloudOAuth 2.01 hourYesUses Oracle IDCS
SAP EWMSAP system user + RFC trustPersistentN/AOData: OAuth 2.0 via BTP
ShipBobAPI key (Bearer token)Does not expireN/AOne key per merchant channel
ShipStationAPI key + secret (Basic auth)Does not expireN/ABase64-encode key:secret
FlexportAPI key (Bearer token)Does not expireN/AScoped per integration

Authentication Gotchas

Constraints

Integration Pattern Decision Tree

START — ERP-to-WMS/3PL Integration
|-- What WMS/3PL system?
|   |-- Manhattan Active WM -> REST API (OAuth 2.0)
|   |-- Blue Yonder WMS -> MOCA (legacy) or Integration API (modern)
|   |-- Oracle WMS Cloud -> REST API (XML/JSON)
|   |-- SAP EWM Embedded -> No external integration needed (shared DB)
|   |-- SAP EWM Decentralized -> IDoc (batch) or OData (real-time)
|   |-- 3PL (ShipBob/ShipStation/Flexport) -> REST API
|   +-- Legacy/custom WMS -> EDI 940/945 via VAN
|-- What's the integration pattern?
|   |-- Real-time order release (<1 min latency)
|   |   |-- < 500 orders/day -> Direct REST API calls, synchronous
|   |   |-- 500-5,000 orders/day -> Event-driven (middleware routes)
|   |   +-- > 5,000 orders/day -> Message queue + async workers
|   |-- Batch order release (scheduled waves)
|   |   |-- EDI 940 via VAN -> Hourly/daily batch files
|   |   |-- File-based (CSV/XML) -> SFTP drop folder
|   |   +-- IDoc batch (SAP EWM) -> Scheduled ALE distribution
|   +-- Hybrid (real-time order + batch inventory) -> Most common pattern
|-- Which data flows?
|   |-- ERP -> WMS: Sales order, PO receipt, transfer orders, item master
|   |-- WMS -> ERP: Ship confirm, ASN (856), inventory adjustments
|   +-- Bidirectional: Inventory levels (real-time WMS, periodic ERP recon)
+-- Error tolerance?
    |-- Zero-loss -> Idempotent APIs + DLQ + reconciliation job
    +-- Best-effort -> Retry with exponential backoff

Quick Reference — Order-to-Ship Process Flow

StepSourceActionTargetData ObjectsEDI EquivalentFailure Handling
1ERPRelease sales order to WMSWMSOrder header, lines, ship-to, priorityEDI 940Retry 3x, then DLQ + alert
2WMSReceive order, validate inventoryWMS (internal)Allocation recordsN/AReject to ERP with reason code
3WMSWave planning + task assignmentWMS (internal)Wave ID, pick tasksN/ARe-wave on failure
4WMSPick, pack, generate shipping labelWMS + carrierCarton contents, tracking #, weightN/AManual intervention queue
5WMSShip confirmation to ERPERPShipment ID, tracking #, shipped qtyEDI 945Retry 3x, then manual reconciliation
6WMS/CarrierASN to customer/retailerCustomerCarton details, PO ref, SSCC-18EDI 856Resend; chargebacks if late
7ERPPost goods issue, update inventory, invoiceERP (internal)Inventory movement, billing docEDI 810Reprocess from ship confirm
8BothNightly inventory reconciliationERP + WMSOn-hand qty by location, lot, serialEDI 846Variance report + cycle count

Step-by-Step Integration Guide

1. Establish connectivity and authenticate

Set up authenticated connections to both ERP and WMS systems. [src1, src3]

# Manhattan Active WM — OAuth 2.0 token request
curl -X POST https://{tenant}.manh.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials&client_id={CLIENT_ID}&client_secret={CLIENT_SECRET}&scope=wm-api"

# ShipBob — API key authentication
curl -X GET https://api.shipbob.com/1.0/order \
  -H "Authorization: Bearer {SHIPBOB_API_KEY}" \
  -H "shipbob_channel_id: {CHANNEL_ID}"

Verify: Successful HTTP 200 response with valid JSON body.

2. Sync item master data (prerequisite)

Before any order flow, ensure item master (SKU) data is synchronized between ERP and WMS. [src7]

{
  "sku": "WIDGET-001",
  "description": "Blue Widget 10-pack",
  "upc": "012345678901",
  "weight": 2.5,
  "weight_uom": "LB",
  "dimensions": { "length": 12, "width": 8, "height": 6, "uom": "IN" },
  "lot_tracked": true,
  "serial_tracked": false,
  "hazmat": false,
  "storage_class": "AMBIENT",
  "erp_item_id": "MAT-100042"
}

Verify: Query WMS for the item by SKU — confirm all fields match ERP source.

3. Release orders from ERP to WMS

Push sales orders from ERP to WMS for fulfillment. [src1, src4]

// Manhattan Active WM REST order release
{
  "orderNumber": "SO-2026-00142",
  "orderType": "SALES",
  "priority": 2,
  "requestedShipDate": "2026-03-05",
  "shipTo": {
    "name": "Jane Smith",
    "address1": "123 Main St",
    "city": "Austin",
    "state": "TX",
    "postalCode": "78701",
    "country": "US"
  },
  "carrier": "FEDEX",
  "serviceLevel": "GROUND",
  "lines": [
    { "lineNumber": 1, "sku": "WIDGET-001", "quantity": 10, "uom": "EA" }
  ]
}

Verify: WMS returns HTTP 201 (REST) or functional acknowledgment 997 (EDI). Order appears in WMS work queue.

4. Receive shipping confirmation from WMS

After pick/pack/ship, WMS sends shipment details back to ERP. [src4, src5]

{
  "orderNumber": "SO-2026-00142",
  "shipmentId": "SHP-88901",
  "shippedDate": "2026-03-04T14:30:00Z",
  "carrier": "FedEx",
  "trackingNumber": "794644790132",
  "lines": [
    { "lineNumber": 1, "sku": "WIDGET-001", "shippedQuantity": 10, "lotNumber": "LOT-2026-A1" }
  ],
  "packages": [
    { "packageId": "PKG-001", "sscc18": "00100123456789012345", "trackingNumber": "794644790132" }
  ]
}

Verify: ERP shows shipment posted, inventory decremented, tracking stored on sales order.

5. Implement inventory reconciliation

Run nightly reconciliation between WMS and ERP to catch drift. [src7]

SELECT w.sku, w.location_id,
  w.on_hand_qty AS wms_qty, e.on_hand_qty AS erp_qty,
  (w.on_hand_qty - e.on_hand_qty) AS variance
FROM wms_inventory w
LEFT JOIN erp_inventory e ON w.sku = e.sku AND w.warehouse_id = e.warehouse_id
WHERE ABS(w.on_hand_qty - e.on_hand_qty) > 0
ORDER BY ABS(variance) DESC;

Verify: Variance report shows zero or known-exception rows only.

6. Configure ASN (EDI 856) for retail fulfillment

If shipping to retailers, generate ASN with SSCC-18 barcodes. Late or missing ASNs trigger chargebacks ($50-$500 per occurrence). [src4, src5]

; EDI 856 — Advance Ship Notice (simplified)
ST*856*0001~
BSN*00*SHP-88901*20260304*1430*0001~
HL*1**S~
TD5**2*FEDX*FG~
REF*CN*794644790132~
N1*ST*Jane Smith~
HL*2*1*O~
PRF*PO-2026-00142~
HL*3*2*P~
MAN*GM*00100123456789012345~
HL*4*3*I~
LIN*1*VN*WIDGET-001*UP*012345678901~
SN1*1*10*EA~
SE*14*0001~

Verify: Retailer EDI system returns 997 functional acknowledgment within SLA.

Code Examples

Python: Order release to ShipBob 3PL

# Input:  Sales order from ERP (order_number, items, ship_to)
# Output: ShipBob order ID and status

import requests  # requests==2.31.0

SHIPBOB_API_KEY = "your_api_key"
CHANNEL_ID = "your_channel_id"

headers = {
    "Authorization": f"Bearer {SHIPBOB_API_KEY}",
    "Content-Type": "application/json",
    "shipbob_channel_id": CHANNEL_ID
}

order_payload = {
    "reference_id": "SO-2026-00142",
    "order_number": "SO-2026-00142",
    "type": "DTC",
    "shipping_method": "Standard",
    "recipient": {
        "name": "Jane Smith",
        "address": {
            "address1": "123 Main St",
            "city": "Austin", "state": "TX",
            "zip_code": "78701", "country": "US"
        }
    },
    "products": [{"reference_id": "WIDGET-001", "quantity": 10}]
}

resp = requests.post("https://api.shipbob.com/1.0/order",
                     json=order_payload, headers=headers)
resp.raise_for_status()
print(f"ShipBob Order ID: {resp.json()['id']}")

JavaScript/Node.js: Poll ShipStation for shipment updates

// Input:  Date range for shipped orders
// Output: Array of shipment objects with tracking numbers

const axios = require('axios'); // [email protected]
const SHIPSTATION_KEY = 'your_api_key';
const SHIPSTATION_SECRET = 'your_api_secret';
const auth = Buffer.from(`${SHIPSTATION_KEY}:${SHIPSTATION_SECRET}`).toString('base64');

async function getShipments(shipDateStart, shipDateEnd) {
  const shipments = [];
  let page = 1, hasMore = true;
  while (hasMore) {
    const resp = await axios.get(
      `https://ssapi.shipstation.com/shipments?shipDateStart=${shipDateStart}&shipDateEnd=${shipDateEnd}&pageSize=500&page=${page}`,
      { headers: { Authorization: `Basic ${auth}` } }
    );
    shipments.push(...resp.data.shipments);
    hasMore = resp.data.pages > page;
    page++;
  }
  return shipments.map(s => ({
    orderNumber: s.orderNumber,
    trackingNumber: s.trackingNumber,
    carrier: s.carrierCode,
    shippedDate: s.shipDate
  }));
}

cURL: Query Manhattan Active WM inventory

# Step 1: Get access token
TOKEN=$(curl -s -X POST https://{tenant}.manh.com/oauth/token \
  -d "grant_type=client_credentials&client_id={ID}&client_secret={SECRET}" \
  | jq -r '.access_token')

# Step 2: Query inventory for specific SKU
curl -s "https://{tenant}.manh.com/api/wm/inventory?sku=WIDGET-001" \
  -H "Authorization: Bearer ${TOKEN}" | jq '.inventory[]'

Data Mapping

Field Mapping Reference — ERP to WMS Order Release

ERP FieldManhattanBlue YonderShipBobTypeGotcha
Sales Order NumberorderNumberordnumreference_idStringShipBob requires unique per channel
Ship-to Address Line 1shipTo.address1adrln1recipient.address.address1StringBlue Yonder: 40-char limit
Requested Ship DaterequestedShipDate (ISO 8601)expdte (YYYYMMDD)N/A (auto)DateFormat varies per system
Item SKUlines[].skuordlin.prtnumproducts[].reference_idStringMust match exactly — no fuzzy matching
Ordered Quantitylines[].quantityordlin.ordqtyproducts[].quantityIntegerBlue Yonder: base UOM only
Lot Numberlines[].lotNumberordlin.lotnumN/AStringShipBob: FIFO only, no lot allocation
Carrier Codecarriercarcodshipping_methodStringNot standardized — maintain mapping table
Prioritypriority (1-5)pckpri (01-99)N/AIntegerScale differs: Manhattan 1=highest
Unit of Measurelines[].uomordlin.uomN/A (always EA)StringShipBob: eaches only

Data Type Gotchas

Error Handling & Failure Points

Common Error Codes

CodeSystemMeaningResolution
429Manhattan / ShipBobRate limit exceededExponential backoff: 2^n seconds, max 5 retries
404Oracle WMS CloudEndpoint not foundPrepend version prefix (e.g., /v9/) to all API paths
400 / INVALID_SKUWMS (any)Item not found in WMSSync item master before releasing orders
422ShipBobUnprocessable entityValidate address and required fields pre-submission
IDOC_ERRORSAP EWMIDoc processing failureCheck WE02/WE05; fix mapping in WE20
997-REDI (any)Functional acknowledgment rejectedReview 997 AK5 segment for specific error codes

Failure Points in Production

Anti-Patterns

Wrong: Polling WMS for order status every minute

# BAD — polling creates load and still has up to 60s latency
while True:
    orders = wms_api.get_orders(status="shipped")
    for order in orders:
        erp.update_shipment(order)
    time.sleep(60)

Correct: Use webhooks or event-driven notifications

# GOOD — WMS pushes ship confirmations as they happen
@app.route('/webhook/wms/shipment', methods=['POST'])
def handle_shipment_webhook():
    payload = request.json
    if db.shipment_processed(payload['shipmentId']):
        return jsonify({"status": "duplicate"}), 200
    erp.post_goods_issue(payload)
    db.mark_shipment_processed(payload['shipmentId'])
    return jsonify({"status": "ok"}), 200

Wrong: Sending orders without validating item master

// BAD — orders with unknown SKUs silently fail
async function releaseOrder(order) {
  await wmsApi.post('/orders', order);
}

Correct: Pre-validate all SKUs against WMS item master

// GOOD — catch missing items before fulfillment delays
async function releaseOrder(order) {
  const wmsCatalog = await wmsApi.get('/items?skus=' + order.lines.map(l => l.sku).join(','));
  const wmsSkus = new Set(wmsCatalog.data.map(i => i.sku));
  const missing = order.lines.filter(l => !wmsSkus.has(l.sku));
  if (missing.length > 0) {
    await syncItemMaster(missing.map(l => l.sku));
  }
  await wmsApi.post('/orders', order);
}

Wrong: Using real-time inventory sync as single source of truth

# BAD — eventual consistency gaps cause silent inventory drift
def get_available_inventory(sku):
    return wms_api.get_inventory(sku)['available']

Correct: Real-time for operations, nightly reconciliation for accuracy

# GOOD — use WMS for real-time ATP, reconcile nightly
def reconcile_inventory():
    wms_snapshot = wms_api.get_full_inventory_snapshot()
    erp_snapshot = erp_api.get_inventory_by_warehouse()
    variances = find_variances(wms_snapshot, erp_snapshot)
    if variances:
        create_cycle_count_request(variances)

Common Pitfalls

Diagnostic Commands

# Check ShipBob API connectivity
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer {API_KEY}" \
  -H "shipbob_channel_id: {CHANNEL_ID}" \
  https://api.shipbob.com/1.0/product?limit=1

# Check ShipStation API connectivity
curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Basic {BASE64_KEY_SECRET}" \
  https://ssapi.shipstation.com/orders?pageSize=1

# Test Manhattan Active WM OAuth token
curl -s -X POST https://{tenant}.manh.com/oauth/token \
  -d "grant_type=client_credentials&client_id={ID}&client_secret={SECRET}" \
  | jq '{token: .access_token[:20], expires: .expires_in}'

# SAP EWM — check IDoc status
# Transaction WE02: filter by message type WMMBXY
# Transaction SM58: check tRFC/qRFC queue for stuck IDocs

# EDI 940 transmission verification
# SPS Commerce portal -> Transactions -> filter Document Type 940
# Check 997 status: Accepted (A) vs Rejected (R)

Version History & Compatibility

SystemCurrent VersionPrevious MajorBreaking ChangesNotes
Manhattan Active WMCloud-native (versionless)Pre-2023 (on-prem)REST replaced SOAPOn-prem to cloud = full API rewrite
Blue Yonder WMS2024.x2022.x (JDA)Integration API replaces some MOCAMOCA still needed for advanced ops
Oracle WMS Cloud24B (REST v9+)21CJSON support added (was XML-only)Version prefix required in URIs
SAP EWMS/4HANA 2023+ECC 6.0 EWMEmbedded removes RFC needDecentralized still uses IDoc/RFC
ShipBob APIv1.0N/AWebhook engine added 2025No breaking changes to date
ShipStation APIv3v2Pagination + rate limits changedv2 deprecated
Flexport API2025-032023-10Products/Parcels APIs addedVersion in URL path
EDI 940/945/856X12 008010X12 005010Minimal — backward compatibleMost partners still on 005010

When to Use / When Not to Use

Use WhenDon't Use WhenUse Instead
Dedicated WMS separate from ERPERP built-in warehouse module meets needsERP-native warehouse configuration
Outsourcing fulfillment to 3PLOwn warehouse with ERP-native WMSERP-native warehouse module setup
Retailers requiring EDI 856 ASNDirect-to-consumer only, no retailer requirementsSimple shipping label integration
500+ orders/day or complex operationsFewer than 100 orders/day, simple pick-pack-shipManual fulfillment or ERP-native shipping
Real-time visibility across multiple warehousesSingle warehouse, single systemERP inventory management
Lot/serial tracking or hazmat complianceSimple consumer goods, no trackingBasic 3PL integration without lot/serial

Cross-System Comparison

CapabilityManhattan Active WMBlue Yonder WMSOracle WMS CloudSAP EWMShipBob (3PL)ShipStation (3PL)
API StyleREST (JSON)MOCA + RESTREST (XML/JSON)OData + IDoc + RFCREST (JSON)REST (JSON)
Auth ModelOAuth 2.0MOCA session + tokenOAuth 2.0 (IDCS)SAP system + OAuthAPI key (Bearer)API key (Basic)
Real-time OrdersYes (REST)Yes (MOCA/API)Yes (REST)Yes (OData/qRFC)Yes (REST)Yes (REST)
Batch OrdersVia middlewareYes (file/EDI)Yes (file import)Yes (IDoc batch)NoYes (CSV import)
EDI 940/945 NativeNoYes (via SPS)Yes (via Oracle IC)Yes (via PI/PO)NoNo
Webhook SupportYesLimitedLimitedNoYes (dashboard)Yes
Inventory Query APIYesYes (MOCA)YesYes (OData)Yes (per SKU)No
Lot/Serial TrackingFullFullFullFullNoNo
Multi-warehouseYesYesYesYesYes (network)No
Deployment ComplexityLow (cloud)High (on-prem/hybrid)Medium (cloud)High (S/4HANA)Low (SaaS)Low (SaaS)

Important Caveats

Related Units