Skip to content
Back to articles
Power Automate

The Bulletproof Way to Bulk Fulfill Sales Orders via Dataverse Web API

This article is a “surgical precision” Power Automate pattern for when the normal Dataverse connector isn’t reliable enough—especially on legacy records. It uses the HTTP action + raw Dataverse Web API authenticated via an Azure App Registration to run a bound action (like FulfillSalesOrder) only against a strictly controlled list of records from an Excel table. The key idea: Excel drives the scope, the flow includes a 1-to-1 match safety valve, and you validate via HTTP status codes and the Dynamics UI so you can bulk-clean records without collateral damage.

March 4, 202612
Share
The Bulletproof Way to Bulk Fulfill Sales Orders via Dataverse Web API

Power Automate + Dataverse Web API: Run Bound Actions Safely (HTTP + App Registration + Excel “Target List”)

1. What this tool is for

This flow architecture uses the raw Dataverse Web API via the HTTP action to bypass the standard Power Automate connectors.

It securely authenticates using an Azure App Registration to execute complex, bound actions (like FulfillSalesOrder) against a strictly controlled list of records.


2. When to use it (and when not to)

Use it when:

  • The standard Dataverse connector is throwing vague errors on legacy records, or
  • You have a massive, specific list of client records that must be updated with zero collateral damage

Do not use it when:

  • A simple 1-step Classic Workflow can achieve the same result without requiring App Registration secrets

3. Pre-flight checklist

Before you even open the Power Automate designer, you must have:

  • The Keys: Azure Tenant ID, Client ID, Client Secret from an App Registration
  • The Access: That App Registration added as an Application User in your Dataverse environment with the correct security roles
  • The List: An Excel file uploaded to SharePoint/OneDrive, formatted as a Table, containing the exact Order Numbers you want to target

4. Step-by-step

We are going to let the Excel file drive the flow so we don't accidentally nuke the wrong records.


Step 1: Get the token (outside the loop)

Add an HTTP action at the very top of your flow to POST to your Azure Entra ID token endpoint.

Crucial structural note: put this step outside your main Excel loop.
If you put this inside the loop, you will hammer auth thousands of times, get throttled, and crash your flow.

Configure the HTTP action like this

Method: POST
URI: https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/token
Headers:

  • Content-Type: application/x-www-form-urlencoded

Body (x-www-form-urlencoded, no spaces):

  • client_id=YOUR_CLIENT_ID&client_secret=YOUR_SECRET&resource=YOUR_ENVIRONMENT_URL&grant_type=client_credentials

Consultant gotchas:

  • Because this is application/x-www-form-urlencoded, do not add spaces around &.
    A space becomes part of your secret and the request fails.
  • Ensure YOUR_ENVIRONMENT_URL does not end with a trailing slash /.

Step 2: Read the target list

Use Excel — List rows present in a table to grab the client’s list of Order Numbers.


Step 3: The cross-check

Add an Apply to each loop over the Excel rows.

Inside the loop, use a Dataverse — List rows action to search for the specific order:

  • ordernumber eq '[Excel Order Number]'

Step 4: The safety valve

Add a Condition inside the loop:

  • length(outputs('List_rows')?['body/value']) is equal to 1

Do not be a hero and run this on thousands of production records without this safety net.


Step 5: The API strike (bound action)

In the If yes branch, add a second HTTP action pointing to the bound action endpoint:

  • https://[org].crm.dynamics.com/api/data/v9.2/salesorders/Microsoft.Dynamics.CRM.FulfillSalesOrder

Pass your token in the headers:

  • Authorization: Bearer [Token]

Use this JSON body:

{
  "OrderClose": {
    "@@odata.type": "Microsoft.Dynamics.CRM.orderclose",
    "subject": "Closed manually to match corresponding order in BC",
    "salesorderid@odata.bind": "/salesorders([Your Dynamic Sales Order ID])"
  },
  "Status": 100001
}

Tags

#power-automate#tips#data#data migration#data movement#metadata#design

Get new articles in your inbox

No spam. Unsubscribe anytime.

Related articles

You might also find these helpful

Customer Voice + D365: Automate Case Surveys, Score Responses, and Flag Negatives
Power Automate

Customer Voice + D365: Automate Case Surveys, Score Responses, and Flag Negatives

This guide is a reusable pattern for connecting Customer Voice + Dynamics 365 Customer Service so survey feedback becomes actionable work. It shows how to automatically send a survey when a Case is created, then parse the response JSON, score specific questions, and write a clear Positive/Negative “Survey Outcome” back onto the Case. The result: support teams can triage unhappy customers directly from Dynamics (no dashboard hopping), with guardrails for exclusions, ALM-friendly question mappings, and safe “no false negatives” scoring.

Mar 2, 202612
Scaling In-Person Event Registration: One ClickDimensions Widget to Rule Them All
Power Automate

Scaling In-Person Event Registration: One ClickDimensions Widget to Rule Them All

Learn how to scale in-person event registrations in Dynamics 365. Use one embedded ClickDimensions form and Power Automate to read utm_content and automatically create Event Participation records without manual data entry.

Feb 26, 202611
Why We Used a Console App to Update 1.3 Million Records (And When You Should Too)
Dataverse

Why We Used a Console App to Update 1.3 Million Records (And When You Should Too)

When your update count hits seven digits, the question stops being “can we do this?” and becomes “what’s the safest way to do this once?” This article explains why a console app using the Dataverse SDK is often the most controlled option for high-volume updates—especially when you need deterministic mapping logic, safe reruns, batching/throttling control, and the ability to update inactive records—plus a practical “test small first” pattern and validation steps to prove it worked.

Feb 24, 202610