Most ERP integration patterns are not chosen. They are inherited from a phrase in a requirements document, and the phrase is almost always “real time”.
Nobody argues with it, because arguing sounds like arguing for a worse system. So the interface gets built synchronously, the two systems quietly become dependent on each other, and the dependency is discovered years later by an incident nobody thinks to connect back to a requirements document. There is a specific case further down.
Microsoft publishes nine patterns for this, with the trade-offs stated. This piece is about choosing between them deliberately.
Nine patterns, and what each one costs
The pattern catalogue is short enough to hold in your head, which makes it usable in a design review:
| Pattern | Use when | The cost of choosing it |
| Real time, synchronous | You genuinely cannot proceed without a current answer | Small payloads only, systems become dependent, sensitive to delays |
| Asynchronous | Almost always | You wait for responses and updates across systems |
| Push | The receiver has a ready API and your skills are on the sending side | Sender cannot see whether the receiver is ready or busy |
| Pull | You cannot add triggers to the sender but it has an API | The sender may not have the APIs you need |
| One-way sync | One system owns the data and others consume it | The receiver may not be able to lock the data read-only, which confuses users |
| Bidirectional sync | There is no clear record keeper | Tricky conflict resolution, data copied per system, some manual reconciliation |
| Aggregation | You need totals rather than detail | Users will eventually want the detail, which means more integration or two systems |
| Embedding | Showing information in another system’s interface | Hard to use that data for calculation or processing |
| Batching | Individual records are not essential | Data is less fresh, and the receiver’s load can spike on arrival |
The sentence in that guidance worth quoting to anyone who insists on synchronous is Microsoft’s own: most recommended integration patterns and technologies are asynchronous, but can feel like real time.
That is the whole argument in one line. The user experience people actually want is achievable asynchronously. The dependency they do not want is what synchronous buys them.
The confusion that causes the most damage
Microsoft flags this directly, and in our experience it is the single most expensive misunderstanding in ERP integration: synchronous patterns and near-real-time patterns get mixed up and swapped for one another.
Their example is the right one. A synchronous pattern looks up current stock in another system and waits for the answer before proceeding. It depends entirely on that system’s speed and availability. A near-real-time pattern updates stock information every few minutes, and lets you carry on working during an outage.
Both look identical in a demonstration. They behave completely differently at 3am when the other system is patching.
The question that separates them is not “how fresh does this data need to be”, because the answer to that is always “as fresh as possible”. It is: what should happen when the other system does not answer? If the acceptable answer is “the process stops”, synchronous is correct and you have chosen it deliberately. If the acceptable answer is “carry on with the last known value”, you wanted asynchronous, and any freshness requirement you were given is really a latency target.
Latency targets are worth writing down properly, and Microsoft’s example is a good template: orders taken on an e-commerce site should reach the warehouse in under five minutes. That is a specification you can design against, test and monitor. “Real time” is not.
Let the record keeper decide the sync pattern
The one-way against bidirectional decision looks like a technical preference and is actually a data ownership question with a technical consequence.
One-way sync establishes a clear record keeper, which makes conflict resolution simple, because there are no conflicts. Bidirectional sync exists for the case where there genuinely is no single owner, and Microsoft is candid about what you take on: tricky conflict resolution, data copied into each system, and some data needing manual updates afterwards.
So the design question comes before the pattern question. If you can name the system that owns a given entity, use one-way sync and accept the one real drawback, which is that the receiving system may not be able to present that data as read-only, and users will try to edit a field that will be overwritten on the next sync. That is a user experience problem with a user experience fix, and it is a much smaller problem than reconciling two writers.
Choose bidirectional only when two systems both legitimately own the same record, which is rarer than it appears. It is often chosen because deciding the owner requires a conversation between two departments, and the integration is easier to build than the conversation is to have.
Design for failure, because the arithmetic is against you
The most useful sentence in the guidance is a statement of probability: the more integration touchpoints you have, the more likely it is that something will go wrong.
That is not pessimism, it is arithmetic, and it means error handling is a design input rather than a phase. The failure modes Microsoft lists are the ordinary ones: system downtime, sign-in issues, hitting platform limits and service caps such as API throttling, process errors and runtime exceptions. None is exotic. All of them will happen.
Two design consequences follow.
Handle errors according to the pattern. For synchronous integrations, decide between retry and rollback based on whether the error is transient or persistent. For asynchronous ones, build queues for review and reprocessing, and set failed messages aside to be fixed rather than losing them.
Make requests idempotent. If a message is sent twice, because of a retry after a failure, the receiving system must process it once. Use message IDs to detect duplicates and out-of-order delivery. Worth knowing that Azure Service Bus does this without extra code, which is a strong argument for using a service bus rather than hand-building retry logic that is subtly wrong in ways that only appear under load.
There is also a warning about monitoring that I would put on the wall: make sure your monitoring system is sturdy enough that it does not become a point of failure itself, and it should never slow down the integrations it watches. The recommended approach is to use the built-in monitoring in the tools you already run rather than building something bespoke, and to let monitoring signals flow asynchronously.
The interfaces we inherit
Most of the synchronous interfaces we inherit were built that way by default rather than by decision. Nobody asked what should happen if the other system does not answer. Somebody wired a call and moved on.
The case that stays with me is a synchronous stock lookup between two systems, where a routine patch window on one side took down order entry on the other. Not an outage. Scheduled maintenance, on a system that order entry was never meant to depend on. The dependency had never been designed at all. It was simply how the interface happened to get built two years earlier.
Two things in that are worth pulling out.
The first is the word “patch window”. A synchronous dependency does not need a failure to hurt you. It only needs the other system to be briefly unavailable, which is something every system is, deliberately, on a schedule. Designing for outages and forgetting maintenance is how these get missed in review.
The second is that Microsoft uses a stock lookup as its own illustration of the synchronous against near-real-time distinction. That is not a coincidence. Stock is the canonical case where the data feels like it must be current, which is exactly what attracts a synchronous call, and exactly where the coupling does the most damage when the other end goes quiet. If your estate has a synchronous stock or availability lookup, it is worth checking first.
Our position: the pattern is an architecture decision, not a build decision
In our view the pattern choice belongs in the architecture, decided once and applied consistently, and the common failure is that it gets made repeatedly by whoever is building each interface.
That is how estates end up with forty integrations built nine different ways, each defensible in isolation, collectively impossible to operate. Nobody decided on that architecture. It accumulated, one reasonable local decision at a time, and the operational cost lands on a support team that was not in any of those conversations.
We would not let “real time” into a requirements document unchallenged. Not because it is always wrong, but because it is almost never examined, and the examination takes one question: what should happen when the other system does not answer.
Across our estates the integrations that age well have three things in common. They are asynchronous, they are idempotent, and they have a named owner for every entity that crosses a boundary. The ones that age badly are usually synchronous by default rather than by decision.
The counterweight, and I want to be fair to it: genuinely synchronous requirements do exist. Credit checks, stock reservation at the point of sale, and payment authorisation are real cases where proceeding on stale data is worse than stopping. When that is true, choose synchronous knowingly, keep the payload small, and design explicitly for what the calling system does when the answer does not arrive.
How many patterns can an estate carry
We would put the pattern decision at architecture level every time, never per interface. The moment each integration team decides for itself, you get an estate that is individually defensible and collectively unmanageable. Every interface has a good reason. Nobody can operate the set.
The threshold we use is deliberately low. Once an estate has more than two or three distinct patterns in active use without a documented reason for each, it is already an operations problem, even if not one of the interfaces is broken.
The qualifier is doing the work there. Two or three is not a hard ceiling, and a fourth pattern with a written reason is fine. What is not fine is a fourth pattern nobody can account for, because that is evidence the decision was made locally and never reviewed.
And this is why pattern sprawl persists for years without anyone funding a fix. The cost shows up as support burden, not as an incident. There is no outage to point at, no post-mortem, no line in a budget. There is just a team that takes progressively longer to diagnose everything, because every interface has to be understood before it can be touched, and no two of them work the same way. Nobody escalates a slow diagnosis.
Where this connects
Two things worth linking, because integration decisions rarely sit alone.
If the ERP itself is moving, the Dynamics migration is the moment to revisit patterns rather than port them. Interfaces get recreated during a migration anyway, and recreating a synchronous interface faithfully is how a bad pattern survives a platform change.
And on the platform underneath, the boundaries matter. Virtual networks cannot be shared across subscriptions, which is one of the four triggers for subscription design: which systems need to talk to each other is an input to how the platform is carved up, not a detail to resolve afterwards.
Where to start
Audit the ERP integration patterns you already run before designing any new ones. Take your existing interfaces and write two columns: the pattern each one uses, and what happens when the other end does not respond. Most estates have never had that written down, and the second column is usually blank or aspirational.
Then ask, for every synchronous interface, whether the process genuinely must stop. Where the answer is no, you have found work worth doing, and it is usually smaller than a rebuild because the endpoints stay the same.
Veratas does the enterprise architecture work that decides these boundaries, and the data integration delivery underneath it.
If you have integrations built nine different ways and an operations team carrying the result, talk to our team. Mapping the patterns is a short exercise and it usually shows that a handful of interfaces cause most of the trouble.
Frequently asked questions
Should ERP integrations be synchronous or asynchronous? Asynchronous in almost all cases. Microsoft states that most recommended integration patterns and technologies are asynchronous but can feel like real time. Choose synchronous only where the process genuinely cannot proceed on stale data.
What is the difference between synchronous and near real time? A synchronous interface waits for an answer before proceeding and depends on the other system’s availability. A near-real-time interface refreshes on a short cycle and lets work continue during an outage. They look identical in a demonstration and behave very differently during an incident.
When should we use bidirectional sync? Only when two systems both legitimately own the same record. It brings conflict resolution, duplicated data and manual reconciliation. If you can name the owning system, one-way sync is simpler and safer.
What is idempotency and why does it matter? It means a message sent more than once is processed only once, which matters because retries after failure are normal. Use message IDs to detect duplicates and out-of-order delivery. Azure Service Bus handles this without extra code.
How should we handle integration errors? By pattern. Synchronous integrations need a retry or rollback decision based on whether the error is transient or persistent. Asynchronous integrations need queues for review and reprocessing, with failed messages set aside rather than lost.
How many integration patterns should an estate have? More than two or three distinct patterns in active use, without a documented reason for each, is already an operations problem even when nothing is broken. The cost appears as support burden rather than incidents, which is why it persists for years without anyone funding a fix.
Why do synchronous interfaces fail during maintenance rather than outages? Because a synchronous dependency does not need a failure to hurt you, only brief unavailability, which every system has deliberately and on a schedule. Designing for outages while forgetting patch windows is how these dependencies survive review.
What should we monitor? Everything contributing to the integration, using the built-in monitoring in tools you already run. Microsoft warns that the monitoring system must not become a point of failure itself and must never slow the integrations down, so signals should flow asynchronously.

Cloud and enterprise architect with 17 years of experience across data platforms, integration and application development. Focus areas include Azure architecture, cloud-native application design, and ERP to data platform integration.






