The Shortcut That Isn't

Here's the scenario. You're building a licensee or customer portal on Power Pages. Somewhere in the requirements is a line like "users can pay their renewal fee online." The portal is already authenticated against Dataverse, the licensee record is right there, and adding a payment amount and a status field to that record — or a related custom entity to track transactions — looks like the fastest path to a working demo.

It is the fastest path to a working demo. It is also how a CRM/portal platform quietly becomes a system of record for financial data it was never designed to govern, audited by nobody, reconciled by nobody, and discovered by your finance team roughly the moment they need a number Dataverse cannot produce.

This isn't a hypothetical. It's the single most common architectural drift I see across Dynamics 365 and Power Pages engagements, and it gets worse in regulated and government contexts specifically — because those are exactly the environments where "we'll clean it up later" collides with audit requirements that don't grant extensions.

What Dataverse Is Actually For

Dynamics 365 and Dataverse are exceptional at what they're built for: managing cases, relationships, records, and business process state. A licensee record, an application status, a case timeline, a document checklist — this is Dataverse's home turf. Model-driven forms, business process flows, and security roles all assume this is the kind of data living inside them.

What Dataverse does not do out of the box is enforce the things a ledger needs: double-entry integrity, immutability of posted transactions, statutory tax handling, multi-currency reconciliation, or the audit trail format your accountant's software — and your auditor — actually expects. You can build approximations of all of this with custom entities, plugins, and enough discipline. You'd be rebuilding, badly and partially, software that already exists and is already correct: your ERP.

The Architecture: Four Systems, Four Jobs

The pattern I build around instead keeps each platform doing exactly what it was designed for, connected — not merged:

Diagram showing Power Pages connected to Dynamics 365/Dataverse and a Payment Gateway, both syncing into an ERP/Accounting System via Power Automate and ledger entries
  • Power Pages owns the customer-facing experience — the forms, the account portal, the thing a licensee actually clicks through.
  • Dynamics 365 / Dataverse owns case, relationship, and licensing data — the record of what is happening and its business process state. Not a ledger.
  • A payment gateway handles card processing under its own PCI compliance scope. No balances, card data, or transaction ledgers get stored in Dataverse.
  • The ERP / accounting system owns the ledger — reconciliation, tax handling, financial reporting. It is the single source of truth for money, full stop.

Power Automate or a custom integration layer is what connects them — not a workaround bolted onto whichever platform happened to be open first, but a deliberate sync: case and licensing data flows from the portal into Dynamics; payment flows from the portal to the gateway; the gateway posts ledger entries to the ERP; and Dynamics and the ERP stay synchronized through an integration layer built for exactly that job.

What This Looks Like in a Plugin

Concretely, this means a Dynamics 365 plugin that fires when a licensee's payment is confirmed should never write directly to a custom ledger entity. It should update the case's payment status — data Dynamics legitimately owns — and raise an integration event for anything that belongs downstream:

// Wrong: Dynamics becomes the ledger
public void OnPaymentConfirmed(IPluginExecutionContext context)
{
    var licenseeId = context.PrimaryEntityId;

    // Custom entity holding running balances, transaction history, tax lines...
    var ledgerEntry = new Entity("new_ledgerentry");
    ledgerEntry["new_licenseeid"] = new EntityReference("account", licenseeId);
    ledgerEntry["new_amount"] = amount;
    ledgerEntry["new_runningbalance"] = CalculateNewBalance(licenseeId, amount);
    ledgerEntry["new_taxamount"] = CalculateTax(amount);
    _service.Create(ledgerEntry);
}

// Right: Dynamics owns its own data, integration owns the handoff
public void OnPaymentConfirmed(IPluginExecutionContext context)
{
    var licenseeId = context.PrimaryEntityId;

    // Dynamics updates what it legitimately owns
    var licensee = new Entity("account", licenseeId);
    licensee["new_paymentstatus"] = new OptionSetValue(PaymentStatus.Confirmed);
    _service.Update(licensee);

    // Everything financial is handed off, not owned
    PublishIntegrationEvent(new PaymentConfirmedEvent
    {
        LicenseeId = licenseeId,
        PaymentReference = context.InputParameters["PaymentReference"],
        CorrelationId = Guid.NewGuid()
    });
}

That event lands wherever it needs to — Power Automate, Azure Service Bus, a Custom API — and the ERP posts the actual ledger entry using the payment gateway's transaction record as the source of truth, not a Dataverse approximation of it. If you haven't set up event-driven messaging between Dynamics and downstream systems yet, that's a deeper topic in its own right — see Event-Driven Dynamics 365 with Azure Service Bus for the full pattern.

Why This Matters More in Government and Regulated Work

In a regulated environment, this isn't just architectural hygiene — it's what makes an audit survivable. When a regulator asks "show me every fee this licensee has ever paid, with tax treatment and reconciliation status," you want that answer coming from the system that was built to answer it, with a native audit trail, not from a custom entity someone built under deadline pressure two years ago that nobody has stress-tested against a real audit.

The same logic applies to the payment side. Storing even partial payment or balance data in Dataverse — even without full card numbers — can pull your Power Pages environment into PCI scope in ways that are expensive and unnecessary to unwind. A dedicated payment gateway is built to carry that compliance burden. Let it.

I've watched this exact pattern play out on a licensee/registrant portal built on Dynamics 365 and Power Pages for a provincial regulatory body: exam scheduling, licensee search, and case status all live correctly in Dynamics, while payment and financial reconciliation are deliberately kept outside it. That separation wasn't a constraint we had to work around — it made the compliance conversation with the client's technology leadership dramatically simpler, because there was no ambiguity about which system owned which fact.

How to Tell You've Drifted

A few honest signals that a Dynamics 365 implementation has taken on ledger responsibilities it shouldn't have:

  • A custom entity has a field literally named runningbalance, balance, or similar.
  • Someone has written a plugin or flow that calculates tax.
  • "Reconciliation" is a manual export-to-Excel process run by someone in finance who dreads it.
  • Card or bank details — even tokenized references beyond a transaction ID — live in a Dataverse table.
  • The answer to "what does the ERP say the balance is?" and "what does Dynamics say the balance is?" is sometimes different.

Any one of these is a sign the boundary has already blurred. None of them are catastrophic on their own, and none require a rebuild — they require an integration layer that was probably deferred under the same deadline pressure that created the shortcut in the first place.

Best Practices Summary

  • Let Dataverse own case and relationship data — never financial systems of record. Balances, tax, and reconciliation belong in the ERP.
  • Route payments through a dedicated gateway. Keep card and balance data out of Dataverse entirely, including tokenized approximations.
  • Treat integration as a first-class layer, not an afterthought. Power Automate, Custom APIs, or Service Bus — pick one deliberately rather than defaulting to whichever is fastest today.
  • Design for idempotency and correlation IDs across every handoff between Power Pages, Dynamics, the gateway, and the ERP.
  • Ask "which system answers this question in an audit?" for every data point before deciding where it lives.
  • Revisit early architecture decisions before they calcify. A boundary that's cheap to fix at month three is expensive to fix after two years of custom entities built around it.

Conclusion

Out-of-the-box Dynamics 365 is never going to be a 100% custom fit for every requirement on its own — no platform is. The goal was never to force it into being one. It's to build the right integration boundaries around it, so each system does the job it was actually designed for, and the seams between them are deliberate rather than accidental.

That discipline costs a little more up front — an extra integration point, a conversation about which system owns what, sometimes a harder sell than "just add a field." It pays for itself the first time an auditor, a finance team, or a new CTO asks a question your architecture can actually answer.