← Back to Portfolio

Finance Proposal Gateway

A six-endpoint Azure Function gateway between Dynamics 365 CE and an external asset-leasing platform

Executive Summary

Sales needed finance proposals raised against an external asset-leasing platform without leaving Dynamics 365. The two systems had no common ground: different identity, different data model, different lifecycle, and a lender that reports status changes by calling back rather than being polled.

I built an Azure Function gateway with six endpoints that sits between them. It brokers OAuth in both directions, reads every secret from Key Vault via managed identity, receives status webhooks from the lender, and produces the proposal documents that come back to the record. Dynamics calls one internal surface; the gateway owns every detail of the external one.

The Problem

The tempting shortcut is to let Power Automate call the external API directly. It works in a demo and it is a liability in production: the credentials end up in connection configuration, the token lifecycle ends up hand-rolled inside flow expressions, and every change the third party makes to their contract becomes an edit across however many flows happen to touch it.

There was also an inbound problem that flows are the wrong tool for. The leasing platform reports progress by calling you, webhooks arriving at unpredictable times, needing verification, needing to be matched to the right proposal record, and needing to be idempotent because a delivery can arrive more than once.

Both problems point the same way: one component that owns the integration, with a contract Dynamics can depend on and the third party cannot see through.

The Solution

The gateway is a single Azure Function app exposing six HTTP endpoints, split across three concerns. Dynamics 365 talks only to the gateway. The gateway talks to the leasing platform, and absorbs every difference between the two.

  • One integration surface. When the third party changes their contract, the change is absorbed in one deployable, not chased across a dozen flows.
  • Token brokering. The gateway authenticates inbound calls from Dynamics and acquires its own tokens outbound, with the lifecycle handled in code rather than in flow expressions.
  • Webhook receiver. Inbound status callbacks are verified, matched to the correct proposal, and applied idempotently so a duplicate delivery is harmless.
  • Document generation. Proposal documents are produced by the gateway and returned to the record, so the finished artefact ends up where the user is already working.

Architecture

Power Automate invokes the gateway from Dynamics 365. The gateway calls the leasing platform over OAuth and REST, receives status webhooks back on its own endpoints, and reads every credential from Key Vault using the function app's managed identity, there is no secret in application configuration for anyone to find.

Dynamics 365 CE Proposal record Power Automate Generated document Azure Function gateway Quote & submit Status & callback Document endpoints Leasing platform OAuth token endpoint Proposal API Status webhooks invoke OAuth + REST webhook Key Vault (managed identity)

The asymmetry is deliberate. Outbound is request/response and synchronous; inbound is a webhook that can arrive at any time, twice. Treating those as two different problems, rather than forcing both through one pattern, is what keeps the retry and idempotency logic comprehensible.

The Six Endpoints

  • Quote. Turns proposal data held in Dynamics into a quote request the leasing platform accepts, and returns the terms.
  • Submit. Submits the proposal for a decision and records the external reference against the Dynamics record.
  • Status. On-demand lookup for when a user wants the current position rather than waiting for a callback.
  • Callback. The webhook receiver: verified, matched to a proposal, and applied idempotently.
  • Document generation. Produces the proposal document from the agreed terms.
  • Document retrieval. Returns the generated artefact back to the record for the user.

Security & Secrets

  • No secrets in configuration. Every credential is read from Key Vault at runtime via the function app's managed identity. Nothing sensitive lives in app settings, in a flow, or in source control.
  • Two OAuth boundaries. Inbound calls from Dynamics are authenticated, and the gateway holds its own client credentials outbound. Neither side ever sees the other's tokens.
  • Verified webhooks. Inbound callbacks are validated before anything is applied, an unauthenticated endpoint that mutates records is an open door.
  • Idempotent by proposal reference. A repeated callback converges on the same state rather than duplicating it, which is the only safe assumption to make about third-party delivery.
  • Least privilege into Dataverse. The gateway's service principal can reach the tables it needs and nothing else.

Technologies

Azure Functions .NET 8 OAuth 2.0 Azure Key Vault Managed Identity Power Automate Dynamics 365 CE Dataverse Web API

Results & Impact

6 Gateway endpoints
2 OAuth boundaries
0 Secrets in configuration
Both Directions covered

Sales raise and track finance proposals without leaving the CRM record, and the finished document arrives back on it. The integration detail (tokens, retries, webhook verification, the third party's data model) stays inside one deployable that can be tested and versioned on its own.

The pattern generalises well beyond leasing. Any time a Power Platform solution needs to talk to a third party that has its own identity model and its own opinions about how it reports state, a thin gateway is worth the extra component: it is the difference between one place to change and every flow you own.

Get in Touch

Building agents on the Power Platform, or trying to get one past a pilot? I am happy to talk it through.

Get in Touch →