The pattern is the easy part. The limits decide it.
Microsoft publishes six integration patterns for Dynamics 365 finance and operations apps, and the right one depends on latency and coupling rather than preference. What decides most projects is not the pattern but the limits underneath it: service protection ceilings enforced per user per server, OData throughput measured in records per hour against a batch API two orders of magnitude faster, business events whose delivery order is explicitly not guaranteed, and a recurring-integrations queue that re-serves an unacknowledged message every thirty minutes. Design for those four and the integration holds. Design around them and it fails quietly, months later, under load.
Where these projects actually fail
Service protection limits
OData throughput
Business events have no ordering guarantee
Recurring integrations re-serve messages
Each one is Microsoft’s published behaviour, with the write-up linked below.
Why an optimization company writes about integration limits
We do not sell integration as a service line. But every optimizer and every agent has the same first problem: read the system of record live, compute something the ERP never calculated, and write the result back without touching core logic or breaking the upgrade path.
That problem is where these engagements actually fail, and it fails late — under production load, on the pattern that tested fine. So the limits below are not background reading. They are the constraints every decision layer we build has to live inside.
Six patterns, and what each is built for
Microsoft's integration overview for finance and operations apps opens by listing six available patterns. The comparison that matters is latency against coupling — how fresh the data is, and how much breaks when either side changes.
Two of the six are batch-shaped and two are event-shaped, which is the split most design reviews actually need. The full comparison, with what each costs, is in the article linked beneath this section.
All six compared, with what each costs →The four limits that decide the design
Each of these is Microsoft's published behaviour, not folklore. Each has a full write-up behind it.
Service protection limits
Three limits are enforced per user per server, and the finance and operations endpoints answer differently from the Dataverse side. The trap is the response to hitting one: a naive retry loop increases the request rate against a limiter that is already throttling you, so the integration degrades faster the harder it tries.
The full write-up →OData throughput
Microsoft's own sizing examples put OData at a peak measured in records per hour, and put the batch data API two orders of magnitude above it. Choosing OData for a bulk job is not a slow choice, it is the wrong instrument. Four specific OData behaviours also make a working integration slower or quietly wrong.
The full write-up →Business events have no ordering guarantee
Microsoft states it under a heading called Limitations: the order in which finance and operations emits business events is not guaranteed to be the order in which they are delivered. The control number is a dedupe key, not a sequence. Consumers have to be idempotent, derive state from the record rather than from the event order, and reconcile against the ERP rather than against the stream.
The full write-up →Recurring integrations re-serve messages
A duplicated document is a redelivery, not a lost message. An unacknowledged message becomes available to dequeue again every thirty minutes until it is acknowledged, and the acknowledgement must echo the dequeue response body. Three common implementation mistakes break that contract, and each produces duplicates that look like a data problem.
The full write-up →The boundary we hold, whatever the pattern
The decision layer reads the system of record as it is, through supported surfaces. A nightly extract makes yesterday's answer, and a planner who catches it once stops trusting the system.
The app returns its own output to its own fields. It does not rewrite records it did not author, which is what keeps the upgrade path and the implementation partner's support intact.
Money or stock moving is proposed and prepared, then approved by someone. That design is what gets an IT director to say yes, and it is stronger than promising autonomy.
OData data entities, custom services and business events, with an Entra app registration mapped to a service role. Reaching around them into the database is what breaks the next update.
Dynamics 365 integration, answered plainly
- Does Business Central have an API?
- Yes — Business Central exposes REST APIs and OData endpoints, and the 2026 wave 1 release adds a built-in MCP server so an agent can call them as tools. Finance and Supply Chain Management is a different product with a different surface: OData data entities, custom services and business events. The difference between the two is most of the expertise in these engagements.
- What are the Dynamics 365 integration patterns?
- Microsoft names six for finance and operations apps. Two are batch-shaped, two are event-shaped, and the choice is decided by latency and coupling rather than preference — how fresh the data has to be, and how much breaks when either side changes.
- Why is our OData integration slow?
- Often because it is the wrong instrument for the job. Microsoft's published sizing examples put OData at a peak measured in records per hour and the batch data API two orders of magnitude above it. Four further OData behaviours can make a working integration slower or quietly wrong.
- Why are we getting duplicate documents from a recurring integration?
- It is a redelivery, not a lost message. An unacknowledged message becomes available to dequeue again every thirty minutes until acknowledged, and the acknowledgement has to echo the dequeue response body. Duplicates almost always trace to that contract being broken rather than to the data.
- Can we rely on the order business events arrive in?
- No, and Microsoft says so under a heading called Limitations. The emission order is not guaranteed to be the delivery order, and the control number is a dedupe key rather than a sequence. Build idempotent consumers that derive state from the record.
- Do you sell integration services?
- No. We build optimization apps and the decision layer beside the ERP, and every one of them has to read and write the ERP safely to work at all. This page is that groundwork, not a service line.
Deep dives from our engineering team

Your optimizer is only as good as its write path. How should it read and write Dynamics 365?
Microsoft's integration overview for finance and operations apps publishes six integration patterns, and two of those six rows are containers holding several documented surfaces each. This is the map an IT buyer should hold before any companion app touches the ERP — what each surface is for, which limits are actually enforced today, what a read costs versus a write, and the thirteen narrower questions underneath this one.
Read more12 min read
Why does your OData integration slow down at a few thousand records an hour?
Microsoft's own integration sizing examples put OData at a peak data volume measured in records per hour, and the batch data API examples two orders of magnitude above it. Here is the table Microsoft publishes, the caveat it attaches, the validate chain that explains the number, and the four OData behaviours that make a working integration slower or quietly wrong.
Read more9 min read
Which Dynamics 365 service protection limits are actually enforced?
The three limits Dataverse actually enforces per user per server, what happens when you cross one, and why a retry loop makes it worse.
Read more9 min read
Why do recurring integrations create duplicate documents?
A duplicated document from a recurring integration is a redelivery, not a lost message. Microsoft documents that an unacknowledged message becomes available to dequeue again every 30 minutes until it is acknowledged, and that the acknowledgement must echo the dequeue response body. Here is the contract in Microsoft's words, the three ways teams break it, one more path that re-serves the same message, one upgrade that breaks your defence against it, and what will not fix any of it.
Read more7 min read
Business events give you no ordering guarantee. What do you build instead?
Microsoft states it under a heading called Limitations - the order in which Finance and Operations emits business events isn't guaranteed to preserve the order in which they're delivered. The control number is a dedupe key, not a sequence. So you build consumers that are idempotent, derive state from the record rather than the event sequence, and reconcile against the ERP rather than against the event stream.
Read more8 min read
Why do your data events never fire for some entities?
Microsoft names the class exactly - when a data entity uses a view as its primary data source, data events don't trigger. Not all views, not all entities - the entity's primary data source. This article gives Microsoft's wording and its stated reasons, the separate temporary-table case that raises an error instead of staying silent, and the published throughput figures that Microsoft says the environment does not explicitly throttle.
Read more8 min read
What does dual-write actually cost you in transaction budget?
A budget with three published lines. Microsoft states a two-minute transaction time limit that includes the time to process standard and custom Dataverse plugins, a ceiling of 1,000 records per single transaction in the finance and operations to Dataverse direction, and a plan of record restricting dual-write to a one-to-one mapping. Every dual-write write spends from all three, and the bill arrives at posting time.
Read more8 min read
Why are virtual tables fast in the demo and slow in production?
Because a demo has one entity, few rows and co-located environments, and production has none of those. Across the virtual entities overview, the virtual entities FAQ and the entity-modeling page, the only virtual entity overhead figure Microsoft publishes is for the co-located case; there is an FAQ answer headed "The virtual entity performance is slow when a virtual entity has relationships to other entities"; and Microsoft states that the exemption applies only to the Finance and Operations endpoints the virtual entity plugin invokes, and that because the request is made through the Dataverse API, Dataverse service protection limits might still apply to it.
Read more8 min read