Back to Blog
Published:
Last Updated:
Fresh Content
ERP Write-Back & IntegrationFoundational guide

Your optimizer is only as good as its write path. How should it read and write Dynamics 365?

12 min read
2,646 words
high priority
Muhammad Mudassir

Muhammad Mudassir

Founder & CEO, Cognilium AI

TL;DR

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.

Your optimizer is only as good as its write path. How should it read and write Dynamics 365?

Microsoft publishes six integration patterns for finance and operations apps. Two of those six rows are containers holding several documented surfaces each, they are not interchangeable, and the wrong choice is discovered late — after the integration works, and before anyone notices what it costs. The map to hold before any companion app touches your ERP.

An optimizer is only as good as its write path

An optimization app reads state out of Dynamics 365, computes the decision the ERP records but does not optimize — the margin-optimal price, the shortest pick path, the safety-stock level that balances service against working capital — then has to put the answer somewhere a person will act on.

The reading is the easy half. The write is where the architecture is decided, because a write carries business logic, a transaction, a security context and a throughput ceiling, and those four are documented on four different Microsoft pages.

The failure mode is not that the integration breaks. It is that it works — in a sandbox, with one legal entity and a thousand rows. Then month-end runs, or master planning deletes and re-creates a few hundred thousand rows, and the surface that was right for a demo turns out to be wrong for the volume. A planner finds that, not a monitor.

Dynamics 365 is the system of record. The optimizer is the system of intelligence beside it. That line is credible only if the seam between them is a documented, supported surface with a named cost. This article is that seam.

Microsoft publishes six patterns, and two of the six are containers

Microsoft's integration overview for finance and operations apps (ms.date 2026-03-09) introduces its table with one sentence: "The following table lists the integration patterns that are available." Six rows follow. Microsoft's names, character-exact, in Microsoft's order:

  • Power Platform integration — What it is, in one line: The shared data layer with Dataverse — a container, expanded below · Status: [GA]
  • OData — What it is, in one line: The synchronous REST endpoint over public data entities · Status: [GA]
  • Batch data API — What it is, in one line: Asynchronous file and package movement — a container, expanded below · Status: [GA]
  • Custom service — What it is, in one line: Your own X++ logic on a SOAP endpoint and a JSON endpoint · Status: [GA]
  • Consume external web services — What it is, in one line: The ERP as the calling client rather than the callee · Status: [GA]
  • Excel integration — What it is, in one line: The Office add-in over OData — a human surface, not an application channel · Status: [GA]

No row on that page carries a preview marker, which is where the [GA] labels come from — an absence of a marker rather than a status stamp. One deployment fact sits directly beneath the table: "For on-premises deployments, the only supported API is the Data management package REST API."

Higher counts are easy to arrive at, because two of those six rows are containers. Microsoft Power Platform integration (ms.date 2026-03-05) names four things under Integration tools for data and business logic: "Together, virtual entities, dual-write, business events, and data events make up the shared data layer for the convergence of finance and operations apps and the Dataverse platform."

Batch data API points at two APIs of its own. Expand both and, by our count off those two pages, the choice is between ten named surfaces rather than six — which is why two architects comparing "Power Platform integration" are often comparing different things.

That page also carries a date worth knowing: "Beginning May 1, 2025, all environments for finance and operations apps must have the Power Platform Integration enabled."

The read path has three shapes, and they answer different questions

An optimizer needs history to fit a model and current state to act on. Those are different reads, and using one surface for both is a common design error.

  • No copy, live — The surface: Virtual tables [GA] · What it is good for: Current state of a named record, with ERP logic and security applied · The documented cost: Latency per call, plus a co-location requirement
  • Analytical copy — The surface: Azure Synapse Link / Link to Fabric [GA] · What it is good for: Model training, features, history at table grain · The documented cost: Refresh interval set in minutes, not current state; plus, where your storage account is firewalled, a live networking change — see ch10
  • Transactional pull — The surface: OData [GA] / Batch data API [GA] · What it is good for: A bounded set of records on your schedule · The documented cost: Throughput, and a throttling contract

The no-copy option is the one that matters most for our positioning, and Microsoft states the mechanism plainly:

"By definition, the data for virtual entities doesn't reside in Dataverse. Instead, it continues to reside in the app where it belongs." — Virtual entities overview (ms.date 2026-01-21)

Two consequences follow, both load-bearing. First: "Because a finance and operations entity is directly invoked in all operations, any business logic on the entity or its backing tables is also invoked." You do not get to skip the ERP's rules by reading this way, which is the point.

Second, on latency: "When finance and operations apps and Dataverse are co-located, the virtual entity overhead is expected to be less than 30 milliseconds (ms) per call." Co-located is doing the work in that sentence.

The analytical copy runs on a different clock, and the choice inside it — Fabric link or Synapse Link — changes what you pay and what you lock in.

The write path is where the cost is, and most of it is not throttling

Start with the constraint that is easiest to get wrong, because the page carrying it opens with a banner. On service protection API limits (ms.date 2026-01-20), Microsoft's current banner reads:

"As of March 31, 2023, user-based service protection API limits are no longer being implemented in finance and operations apps environments. … In version 10.0.35, the API limits are disabled by default but can still be optionally enabled for environments. In version 10.0.36, the limits are disabled on all environments, and the option to enable the limits is removed."

What is enforced on that page is resource-based: "Finance and operations apps environments version 10.0.19 and later enable resource-based service protection API limits." Those throttle on aggregate web-server resource utilisation, not on your request count, which means your integration can be throttled by someone else's job.

Same page, on scope: service protection API limits "aren't available for on-premises or development environments."

Now the costs that are not throttling. Three are from the integration overview, two from Maximize API throughput (ms.date 2026-01-20):

  • Business logic runs — Microsoft's own wording: "If you use OData to insert product records, the records are immediately inserted as part of the OData call" · Where it bites: A write is a transaction, not a row update
  • Batch size is capped — Microsoft's own wording: "In finance and operations apps, batch size is limited to 5,000 operations" · Where it bites: Bulk write design
  • Big batches are the wrong instinct — Microsoft's own wording: "Most scenarios are fastest if you send single requests and use a high degree of parallelism" · Where it bites: Throughput tuning
  • Volume changes the pattern — Microsoft's own wording: "If the volume is more than a few hundred thousand records, use the batch data API for integrations" · Where it bites: Anything at master-planning scale
  • Outbound calls need TLS 1.2 — Microsoft's own wording: Production and sandbox "support only secured communication that uses Transport Layer Security (TLS) 1.2 or later" · Where it bites: The ERP calling your service

Microsoft attaches a caveat to its own sizing examples, and it belongs above the numbers: "Use these numbers only to gauge the pattern and don't consider them as hard system limits."

With that in place: the published OData scenarios are sized at one thousand and five thousand records per hour, the batch data API scenarios at two hundred thousand and three hundred thousand. That is the shape of the decision, not a benchmark.

How we build it: supported surface in, Azure in the middle, approval on the way back

This is our position, stated as a capability rather than as a report on somebody's deployment.

An Optimizer reads through a supported surface, computes on Azure, and writes the optimized decision back through the same surface — behind a human approval step, inside a named Security Role, without modifying a single ERP object. Four commitments, each with a reason:

  • Read through a published surface, never the database — Microsoft states the boundary on its own BYOD page: "The application doesn't allow T-SQL connections to the production database"
  • Compute outside the ERP — Optimization is a modelling workload. Running it inside the transaction that writes the answer couples a model's runtime to a user's save
  • Write back behind a human approval step — An optimizer proposes; a planner disposes. The approval step is what makes a wrong number a rejected suggestion instead of a posted document
  • Run as a named Security Role, not as an administrator — The virtual-entity path already ships one — Microsoft names the out-of-box role CDSVirtualEntityApplication

That last row is the whole of it. On the virtual-entity path all calls are service-to-service, and Microsoft's Architecture section states the consequence: the adapter web API "looks up the associated user in finance and operations apps and runs the query in the context of that user", so "the S2S call doesn't need explicit access to all the finance and operations entities. Instead, it can rely on the privileges of the user who is invoking the action to determine data access."

The optimizer inherits your ERP's security model rather than working around it. On that path nothing is granted that a person could not already do.

We don't touch your ERP core — we surround it with intelligence. Read as marketing, that is a slogan. Read as a design, it is: no new tables in Finance and Operations, no X++ on the posting path, and no schema change your implementation partner has to regression-test at the next Release Wave.

The thirteen questions underneath this one

Every one of these is a decision an architect makes once and lives with. Each links to the article that settles it.

Chapter 13 is the one to read if you receive orders electronically, because inbound documents are where duplicate-creation, ordering and bulk-load problems arrive together rather than one at a time.

Where we would draw the line

We would not put optimization logic inside Finance and Operations. The moment a model lives in X++ on the posting path, it is your implementation partner's problem at every Release Wave and ours at none of them — the wrong division of labour.

We would not write to a Dynamics 365 table directly, and we would not read from the production database even where somebody offers us the connection string. Microsoft documents the virtual-table path and the OData path as invoking the entity's own business logic; a direct write invokes neither.

We would not choose the network topology, the storage account or the private-endpoint design. That belongs to your platform team and your implementation partner. We ask which surface the data takes and who controls it, then build against the answer.

And we would not accept a design where an optimizer writes a posted document with no person in the loop — because the first time it is wrong you want a rejected suggestion in a queue, not a credit note.

What to do this week

  1. Establish which patterns are already live. In Lifecycle Services, check whether the Power Platform integration is enabled; in Power Apps, open Link data and read what sits under Fabric Links and Other Links. Both navigation paths are Microsoft's, cited below.
  2. Find your version number. In Finance and Operations, go to Help & Support > About. Whether you are above or below 10.0.36 decides which paragraph of the limits page applies to you.
  3. Ask what each existing integration writes, and under whose identity. A service principal holding the system administrator role is the thing to look for, and the cheapest thing here to fix.
  4. Pick the decision you most want optimized and trace its data both ways. Which surface reads the inputs, which writes the answer, who approves it. If that path cannot be drawn on one page, it is not yet a design.

About Cognilium Cognilium is the AI optimization layer for Dynamics 365 — complementary apps that optimize the pricing, inventory, warehouse and planning decisions your ERP manages but can't optimize. Built on Power Platform, Dataverse and Azure. https://cognilium.ai · https://www.linkedin.com/company/37180269/

If you are about to let any companion app near your ERP, the write path is the review that matters. Book a fifteen-minute call and we will walk your read and write path with you — which surface, whose identity, which approval step. No deck. https://cognilium.ai

Sources

Sources

Share this article

Muhammad Mudassir

Muhammad Mudassir

Founder & CEO, Cognilium AI

Mudassir Marwat's argument is that ERP systems record decisions they never optimise.

Founder & CEO of Cognilium AI; 37 AI agents in production across four products; 4 production AI products built and operated; three clouds in production (AWSGCPAzure)
Agentic AIRAG → GraphRAG retrievalVoice AIMulti-Agent Orchestration
Next in this series
Why does your OData integration slow down at a few thousand records an hour?
Chapter 1 · 9 min
In short

Key takeaways

  • An optimizer is only as good as its write path, because a write to Dynamics 365 carries business logic, a transaction, a security context and a throughput ceiling — and those four constraints are documented on four different Microsoft pages.
  • Microsoft's integration overview for finance and operations apps publishes its patterns as a table, and two of those rows are containers that expand into several named surfaces each — so two architects who agree on the pattern can still be comparing different things.
  • Microsoft's virtual entities page states that the data doesn't reside in Dataverse, that every call invokes the entity's own business logic, and that the query runs under the calling user's security — which is what makes a companion app a companion rather than a second system of record.
  • Microsoft's service protection page carries two limit types: its own banner states the user-based limits are disabled on current versions with the option to enable them removed, and the resource-based limits it says are enforced throttle on aggregate web-server utilisation — so a well-behaved integration can be throttled by someone else's job.
  • The design we build reads through a published surface, computes on Azure and writes back behind a human approval step inside a named Security Role, so it changes no ERP object — which is what makes it survivable across a Release Wave.
What goes wrong

Common mistakes to avoid

  • Choosing the integration surface from the demo's data volume. Microsoft attaches a caveat to its own sizing examples telling you to use the numbers to gauge a pattern and not as hard system limits, and the pattern that is correct for a sandbox is routinely wrong at master-planning scale.
  • Designing against the user-based service protection limits. Microsoft's banner on that page states they are disabled on current versions; quoting them as a live constraint is the tell that the doc was read but not its banner.
  • Granting an integration the system administrator role because a permission error appeared once. Microsoft ships a scoped role for the virtual-entity path, and the supported surfaces already run queries under the calling user's own entity and row security.
  • Treating the analytics copy and the live read as one surface. Model features and current state have different freshness, and an optimizer that acts on the analytical copy is acting on a copy whose refresh interval is set in minutes, not on current state.
  • Putting the optimization logic inside the ERP. It couples your model's release cycle to your implementation partner's, and it makes every Release Wave a regression test of your data science.

Terms in this article

Definitions in the Cognilium glossary.