Integration Patterns
Most ERP development is integration. An ERP with 40 interfaces is normal; 150 is common in a large enterprise. This is where you’ll spend most of your career.
The integration landscape
┌─────────┐
CRM ────────┐ │ ERP │ ┌──── Banks
E-commerce ─┤ │ │ ├──── Tax authority
Marketplace ┼─────────────▶│ │◀───────────┼──── Customs
POS ────────┤ │ │ ├──── Carriers
Supplier │ │ │ ├──── 3PL / WMS
portals ────┘ │ │ ├──── MES
│ │ ├──── Payroll provider
Warehouse ◀───────────────▶│ │◀──────────▶├──── Tax engine
MES ◀───────────────▶│ │ ├──── Credit bureau
PLM ◀───────────────▶│ │ └──── BI / warehouse
└─────────┘
The four styles
| Style | Latency | Coupling | Use |
|---|---|---|---|
| File transfer | Hours | Loosest | Bulk, legacy, banks, payroll |
| Shared database | Instant | Tightest | Avoid. Two systems owning one schema |
| RPC / API | Milliseconds | Medium | Real-time queries and commands |
| Messaging / events | Seconds | Loose | Async notification, decoupled processing |
Shared database integration is an anti-pattern in almost every case: neither system can change its schema, transactions cross ownership boundaries, and there’s no contract. The exception is a read-only replica for reporting.
Synchronous vs asynchronous
SYNCHRONOUS
Caller ──request──▶ ERP ──▶ process ──▶ response ──▶ Caller
✅ Immediate result, simple error handling
❌ Caller blocked; ERP downtime breaks the caller; slow calls cascade
ASYNCHRONOUS
Caller ──message──▶ Queue ──▶ ERP processes later
│
└──▶ callback / webhook / polling for the result
✅ Resilient, absorbs load spikes, ERP can be down briefly
❌ No immediate answer; needs status tracking and correlation
The rule: synchronous for queries and for things a human is waiting on (stock check, price check, credit check). Asynchronous for commands that change state (create order, post invoice, confirm shipment).
Never make document posting depend on a synchronous external call. Post first, then submit asynchronously with retries. An outage at a tax portal or a carrier API should not stop your ledger.
The canonical integration flow
Source ──▶ Extract ──▶ Transform ──▶ Validate ──▶ Load ──▶ Confirm
│
Error queue ──▶ Human ──▶ Reprocess
Every one of those steps needs to exist. The most commonly skipped are validate (garbage arrives and posts) and confirm (nobody knows whether it worked).
Idempotency and ordering
Two properties every interface needs:
Idempotency — see Concurrency and Idempotency. Derive the key from the business event, never from a per-attempt UUID.
Ordering — some messages must be processed in sequence:
CustomerCreated → CustomerUpdated → OrderCreated
Options: a single partition per key (all messages for customer 100 in order), sequence numbers with buffering for out-of-order arrivals, or designing messages to be order-independent (full-state snapshots rather than deltas).
Full-state messages are usually better than deltas for master data. “Here is customer 100 as it now stands” is idempotent and order-tolerant. “Increment the credit limit by 5,000” is neither.
Error handling
Transient (network, timeout, 503) → retry with exponential backoff + jitter
Validation (bad data) → dead letter, notify the source, do NOT retry
Business (period closed, credit block)→ dead letter with a business-readable reason
Unknown → dead letter, alert, investigate
Classify errors. Retrying a validation error 500 times helps nobody and hides the real problem. Retrying a transient error zero times loses data.
Dead letter queues need: the payload, the error, the retry history, an owner, an alert, and a reprocess action. A DLQ nobody monitors is data loss with extra steps.
Reconciliation
Every interface needs a reconciliation process. This is the most-skipped and most-valuable practice in ERP integration.
Daily:
Source sent: 1,247 orders
Target received: 1,247
Target processed: 1,243
Errors: 4 ← listed, with reasons and owners
Value sent: 4,882,140
Value processed: 4,871,320
Difference: 10,820 ← must be explained
Publish it every morning. Without reconciliation, an interface that silently drops 2% of messages runs for months before anyone notices — usually when someone asks why a customer’s account doesn’t balance.
Middleware
| Approach | When |
|---|---|
| Point-to-point | 1–5 interfaces. Simple, becomes spaghetti beyond that |
| ESB / iPaaS | 10+ interfaces. Central routing, transformation, monitoring |
| Event broker (Kafka, RabbitMQ, EventBridge, Pub/Sub) | Event-driven architecture, many consumers per event |
| API gateway | Managing inbound APIs: auth, rate limiting, versioning |
Common ERP middleware: SAP PI/PO and Integration Suite (CPI), MuleSoft, Dell Boomi, Azure Integration Services (Logic Apps + Service Bus), Oracle Integration Cloud, Workato, Celigo, TIBCO, webMethods.
POINT TO POINT (n² connections) HUB AND SPOKE (n connections)
A ──── B A ──┐
│ ╲ ╱ │ B ──┼──▶ HUB ◀──┬── D
│ ╳ │ C ──┘ └── E
C ──── D
The n² problem is real: 10 systems point-to-point is up to 45 interfaces to build and maintain. It’s the standard argument for middleware, and it’s a good one past about 8 systems.
Master data integration
The hardest integration problem, because it’s about authority, not plumbing.
Who owns the customer record?
CRM creates prospects → ERP creates the billing account?
Or ERP is the master and CRM subscribes?
What if both can create?
Patterns:
| Pattern | Description |
|---|---|
| Single master | One system creates; all others subscribe read-only. Cleanest |
| Federated | Different systems own different attributes (CRM owns contact preferences, ERP owns credit terms) |
| MDM hub | A dedicated system owns the golden record; all others subscribe |
| Bidirectional sync | Both can create/edit. Avoid — conflict resolution is unsolvable in general |
Decide master data ownership on day one of the project. Every unresolved ownership question becomes a data quality problem within six months.
Cross-reference tables are mandatory:
external_id_map(
entity_type, -- CUSTOMER | MATERIAL | ORDER
internal_id,
external_system, -- SALESFORCE | SHOPIFY | WMS
external_id,
synced_at,
PRIMARY KEY (entity_type, external_system, external_id)
);
Never assume IDs match across systems. They never do.
Common ERP integrations and their traps
| Integration | Trap |
|---|---|
| E-commerce → ERP orders | Order volume spikes; payment status vs order status; guest checkout has no customer master |
| ERP → WMS | Partial picks; the WMS must work offline; batch determination ownership |
| ERP → MES | High-frequency confirmations swamping the ERP; aggregate first |
| Bank statements → ERP | Format variety; text parsing for references; a missing day |
| ERP → payment file | Signature, dual control, no post-approval edits |
| CRM ↔ ERP | Master data ownership; duplicate customers |
| ERP → tax engine | Synchronous latency; must have a fallback rate |
| ERP → e-invoicing portal | Government API downtime; clearance status machine |
| Carrier / 3PL | Every carrier’s API is different; status code mapping |
| Payroll provider | Sensitive data; strict encryption; monthly cadence with a hard deadline |
| PLM → ERP | eBOM vs mBOM transformation; engineering change effectivity |
Security
- Authentication: OAuth 2.0 client credentials or mTLS. Not basic auth over the internet
- Named service accounts per interface, least privilege, never shared
- Secrets in a vault, rotated, never in config files or source control
- Transport: TLS 1.2+ everywhere; SFTP with key auth for files
- Payload encryption for sensitive data (payroll, personal data) even over TLS
- IP allowlisting where the partner supports it
- Signature verification on inbound webhooks
- Rate limiting on inbound APIs
- Audit log of every message: who, when, what, and the outcome
Interface service accounts are a common audit finding. One shared “API user” with wide permissions, credentials in a config file, no rotation. Name them, scope them, vault them.
Monitoring
| Signal | Alert on |
|---|---|
| Message throughput | Sudden drop (a silent interface is worse than a failing one) |
| Error rate | Above threshold |
| Queue depth | Growing |
| Processing lag | Above SLA |
| DLQ depth | Anything > 0 for critical interfaces |
| Reconciliation difference | Non-zero |
| Partner API availability | Down |
| Certificate expiry | 30 days out — expired certs are a top cause of interface outages |
Design checklist for any interface
- Documented contract: schema, fields, cardinality, examples
- Versioned contract with a deprecation policy
- Idempotency key derived from the business event
- Ordering requirements identified and handled
- Error classification: transient vs validation vs business
- Retry policy with backoff and a cap
- Dead letter queue with an owner and an alert
- Reconciliation report, published daily
- Monitoring and alerting configured
- Named service account, least privilege, vaulted secrets
- Volume tested at peak (month-end, Black Friday, season)
- Behaviour defined when the partner is down
- Behaviour defined when the ERP is down
- Runbook: how to replay, how to reconcile, who to call