n8n Microsoft Dataverse Node Tutorial: Automate Dynamics 365 Data (2026)

Introduction

If your customer data lives in Dynamics 365 or Power Platform, it lives in Microsoft Dataverse, and until recently n8n reached it only through the HTTP Request node or a community install. The native Microsoft Dataverse node, added in n8n 2.40.0, ships six row operations and a dedicated Entra ID based OAuth2 credential. This tutorial covers the full setup: registering the Entra app, picking the right OAuth2 grant, running every row operation, querying with OData and FetchXML, and using the node as an AI agent tool.

Quick answer

Add the Microsoft Dataverse node (n8n 2.40.0+), create a Microsoft Dataverse OAuth2 API credential with an Entra ID app registration, then use the Row resource to create, get, list, update, upsert, or delete rows in any standard or custom table.

Evidence

Two numbers should shape any Dataverse sync design. First, Microsoft’s service protection API limits documentation caps Dataverse at 6,000 requests per user per web server inside a five-minute sliding window, with a combined execution-time budget of 20 minutes, as of October 2026. A scheduled n8n loop paging tens of thousands of rows one request at a time will hit that ceiling; this tutorial uses the node’s built-in pagination instead of manual loops. Second, the node’s own paging numbers from the official n8n Microsoft Dataverse node documentation: Get Many defaults to a Limit of 50 rows, and a Limit of 5,000 or less is also sent as $top; crossing 5,000 rows needs Row Count ($Top) unset with Return All on or Limit raised.

The n8n 2.40 release notes (September 15, 2026) put it plainly: the new core node supports “Create, Update, Upsert, Delete, Get, and List Rows operations against a Dataverse environment”, and it “uses a new Microsoft Dataverse OAuth2 API credential built on Microsoft Entra ID, supporting Authorization Code or Client Credentials grant types, with automatic token handling, pagination for large result sets, and built-in retry logic for transient errors.” That paragraph is this tutorial’s design brief: six operations, two grants, handled plumbing.

Prerequisites

  • n8n 2.40.0 or newer. Confirm the version at the bottom-left of the editor.
  • A Microsoft 365 tenant with a Dataverse environment.
  • Permission to register applications in Microsoft Entra ID, plus admin access to the environment for the Client Credentials path.
  • The environment URL, found in the Power Platform admin center under the environment’s details, for example https://contoso.crm.dynamics.com.
  • Basic comfort with the n8n canvas. If database nodes are new to you, our n8n Postgres tutorial teaches the same row-operation mental model against PostgreSQL first.

Step 1: Confirm your n8n version and find the node

In any workflow, add a node and search for “Microsoft Dataverse”. On n8n 2.40.0 or newer it appears with a Resource selector set to Row and six operations: Create, Create or Update, Delete, Get, Get Many, and Update. If the search finds nothing, upgrade with our self-hosted n8n upgrade guide. Skip community Dataverse nodes as a workaround; their credential types differ.

Step 2: Register an application in Microsoft Entra ID

Both grant types start with an Entra ID app registration. In the Entra admin center, go to App registrations, New registration. Name it n8n Dataverse and choose Accounts in this organizational directory only. For Authorization Code, copy the OAuth Redirect URL from the n8n credential editor, set Redirect URI to Web, and paste it exactly; for Client Credentials, leave the redirect URI empty. Select Register, then copy the Application (client) ID and Directory (tenant) ID from the Overview page into Client ID and Tenant ID in n8n.

Step 3: Generate a client secret

In the app registration, open Certificates and secrets, Client secrets, and select New client secret. Add a description and expiry, then copy the secret’s Value immediately, not its Secret ID; Microsoft shows the value only once. In n8n, set Authentication to Client Secret, paste the value into Client Secret, and keep it inside the credential, never in workflow fields.

Step 4: Create the Microsoft Dataverse OAuth2 API credential

Create a credential of type Microsoft Dataverse OAuth2 API in n8n:

  • Grant Type: Authorization Code for user-delegated access, or Client Credentials for app-only access.
  • Client ID: the Application (client) ID from Step 2. Client Secret: the secret Value from Step 3.
  • Tenant ID: the Directory (tenant) ID. Use the tenant GUID for Client Credentials; common is for multi-tenant Authorization Code apps only.
  • Environment URL: the environment’s HTTPS base URL, such as https://contoso.crm.dynamics.com. Do not append /api/data/v9.2, a table name, or an application path.
  • National Cloud: Global (Public Cloud) by default (https://login.microsoftonline.com); US Government GCC High and DoD use https://login.microsoftonline.us, China 21Vianet uses https://login.partner.microsoftonline.cn.

Token URLs and scopes are derived automatically from these fields.

Step 5: Configure the grant you chose

Authorization Code. In the app registration, go to API permissions, Add a permission, Dynamics CRM, Delegated permissions, and select user_impersonation (Access Dynamics 365 as organization users). Get admin consent if needed, and give the signing-in user environment access plus a security role with the needed table privileges. In n8n, set Grant Type to Authorization Code, verify the redirect URI matches the credential editor’s OAuth Redirect URL, select Connect my account, sign in, and save.

Client Credentials. In the Power Platform admin center, go to Manage, Environments, select your environment, then Settings, Users + permissions, Application users, New app user, Add an app. Find the Entra registration by application ID, select Add, choose the Business Unit, assign security roles with the privileges the workflow needs, then Create. In n8n, set Grant Type to Client Credentials, enter the tenant GUID, and save. No sign-in is needed, and this flow requires neither user_impersonation nor Microsoft Graph permissions.

Saving the credential triggers a test call to GET /api/data/v9.2/WhoAmI. Treat a pass as connectivity proof only: a token does not prove table access. The n8n Microsoft Dataverse credential guide states this caveat explicitly; it is the top cause of “connected but reads fail” confusion.

Step 6: Create your first row

Add a Microsoft Dataverse node with Resource set to Row and Operation to Create. In Table Name or ID choose From List and pick accounts, the standard table behind Dynamics 365 customer records. The manual By ID entry expects the Web API entity set name (accounts, contacts), not the display name or GUID.

Keep Input Mode at JSON and enter this object in Row Item (JSON), using column logical names as keys:

{
  "name": "Contoso",
  "accountnumber": "ACC-001",
  "numberofemployees": 25,
  "creditonhold": false
}

Execute the node; the output is the row Dataverse returned after the write. Prefer JSON over the Fields key/value mode whenever types matter. The node also rejects an empty row item, so always provide at least one field.

Step 7: Read and update rows

Get. Change the operation to Get, keep accounts, and in Row ID pick the row you created From List or paste its GUID By ID (standard shape, e.g. 00000000-0000-0000-0000-000000000001).

Update. Switch to Update, select the same Row ID, and send only the changed fields, e.g. {"telephone1": "555-0100"}; Update never creates a missing row, unlike upsert.

Lookups. For a single-target lookup such as primarycontactid, supply the row GUID or a reference like /contacts(<contact-id>). For multi-target columns such as Customer, or the Owner column, use an explicit reference (/accounts(<account-id>), /contacts(<contact-id>), /systemusers(<user-id>), /teams(<team-id>); leading slash optional) or an explicit binding with the exact case-sensitive navigation property name. To clear a single-target lookup, send null.

Step 8: Upsert with an alternate key

Set the operation to Create or Update and the table to accounts. For Identifier Type choose Alternate Key and enter a predicate such as accountnumber='ACC-001' (predicate only: no table name, no parentheses, quotes around string values). The alternate key must already exist on the table in Dataverse.

Under Options, Behavior controls the write: Create or Update (default) creates or updates, Update Only fails when the row is missing, Create Only fails when it already exists. Send {"name": "Contoso"} with the default behavior and account ACC-001 is created on the first run and updated on every later run, making scheduled syncs idempotent. Partitioned elastic tables expose no Partition ID option on writes: include partitionid in the row JSON when creating, and for upserts use an Alternate Key predicate with the primary key plus the partition ID.

Step 9: Query with Get Many (OData)

Select Get Many, set Table Name or ID to accounts, and build a query: to fetch up to 100 active accounts whose names start with Contoso, leave Return All off, set Limit to 100, open Options, select name and accountnumber under Select Column Names or IDs, set Filter Rows to statecode eq 0 and startswith(name,'Contoso') (no $filter= prefix), and sort by name ascending. Add an Expand Query such as primarycontactid($select=fullname) for related rows. Each row returns as a separate n8n item.

Limit is the n8n-side cap; the node follows @odata.nextLink until it reaches the limit or runs out of pages, and a Limit of 5,000 or less is also sent as $top. Row Count ($Top) is an explicit server-side cap that takes precedence and disables server-driven paging.

Step 10: Query with FetchXML when you need it

Teams porting Power Platform queries can paste FetchXML into Options, FetchXML Query, for example this query fetching up to 50 active accounts:

<fetch top="50">
  <entity name="account">
    <attribute name="name" />
    <attribute name="accountnumber" />
    <filter>
      <condition attribute="statecode" operator="eq" value="0" />
    </filter>
  </entity>
</fetch>

Two traps: FetchXML uses the table’s logical name (account) while Table Name or ID uses the entity set name (accounts), and the node does not paginate FetchXML, so combining it with Return All errors out. Use OData for automatic pagination.

Step 11: Delete and read the metadata

Switch to Delete, keep accounts, and supply a throwaway Row ID; success returns {"success": true, "id": "<row-id>"}. Every operation except Delete offers Options, Return Full Metadata (off by default) for OData annotations such as formatted values. The node passes columns and annotations through unchanged; see the Dataverse Web API reference for the raw shape.

Step 12: Use the node as an AI agent tool

The node shipped with a tool variant, so it slots into agent workflows directly. A practical pattern: expose Get Many scoped to the contacts table and let the agent query Dataverse itself before answering, instead of you hard-coding the lookup. The tool-calling mechanics are the same as for any data tool, covered in our n8n AI agent tutorial; scope the tool’s table and columns tightly. For failure handling inside agent loops, our n8n error handling guide shows how to catch the NodeApiError values this node surfaces.

Troubleshooting

Table or column pickers do not load. Read the HTTP status and Dataverse error in the picker; it usually implicates the credential or environment URL. Confirm the URL has no /api/data/v9.2 suffix, and fall back to entering the entity set name with Table Name or ID set to By ID.

A lookup value is rejected. Never use a display name as a lookup value. Use a GUID for single-target lookups, or a reference with the entity set name and row ID; Customer and Owner columns need an explicit target table.

Get Many returns fewer rows than expected. Check Limit, remove Row Count ($Top) when you need paging, and confirm the query is OData; FetchXML never paginates in this node.

The credential test passes but operations fail with 401 or 403. The save-time test only calls WhoAmI, which proves the token works, not table access. For Client Credentials, confirm the application user exists with security roles covering your tables. For Authorization Code, confirm environment access, a security role, and the user_impersonation grant.

Upsert creates duplicates instead of updating. The alternate key was not configured on the table before the workflow ran. Define it in the Power Platform maker portal on the addressed column, publish, and rerun. Also verify the predicate: accountnumber='ACC-001', no table name, no parentheses, quotes around string values.

Large syncs hit 429 throttling. Dataverse enforces 6,000 requests per five minutes per user per web server. Prefer one Get Many with Return All over hundreds of Get calls, and respect the Retry-After header.

FAQ

Which n8n version includes the Microsoft Dataverse node? You need n8n 2.40.0 or newer, released September 15, 2026; the version is shown at the bottom-left of the editor. On older releases, upgrade first with our self-hosted n8n upgrade guide.

Should I use the Authorization Code or the Client Credentials grant? Use Authorization Code when the workflow acts as a signed-in user: delegated permissions with auto-renewing refresh tokens, but it needs a redirect URI and an interactive sign-in. Use Client Credentials for scheduled, app-only workflows: no sign-in, but you must create an application user in the environment with security roles.

Can the Dataverse node run inside an AI agent workflow? Yes. The node shipped with a tool variant, so attach it as a tool in an AI Agent workflow, for example letting the agent look up a contact by GUID before drafting a reply.

What is the difference between Limit and Row Count ($Top) in Get Many? Limit is the n8n-side cap; at 5,000 or less it is also sent to Dataverse as $top, and the node follows @odata.nextLink until the limit is reached. Row Count ($Top) is an explicit server-side cap that takes precedence and disables server-driven paging.

Why does my FetchXML query fail when Return All is on? The node does not paginate FetchXML, so pairing a FetchXML query with Return All errors out. Turn Return All off and cap rows with Limit; use an OData query for automatic pagination.

Do I still need a community Dataverse node? No. The built-in node covers create, read, update, upsert, and delete on standard and custom tables. Older community nodes remain useful only for niche extras like read-only SQL over the TDS endpoint.

Conclusion

You now have the full loop: an Entra ID app registration with the right grant, a tested credential, and hands-on runs of all six row operations plus OData and FetchXML queries. Next, use idempotent upserts on alternate keys for scheduled syncs and the agent-tool wiring from Step 12 for conversational CRM access. A natural follow-up is our n8n Postgres tutorial, or the Zapier to n8n migration guide if this is part of a larger platform move. Browse the full tutorials index.

Frequently asked questions

Which n8n version includes the Microsoft Dataverse node?

You need n8n 2.40.0 or newer, released September 15, 2026; the version is shown at the bottom-left of the editor. On older releases, upgrade first with our self-hosted n8n upgrade guide.

Should I use the Authorization Code or the Client Credentials grant?

Use Authorization Code when the workflow acts as a signed-in user: delegated permissions with auto-renewing refresh tokens, but it needs a redirect URI and an interactive sign-in. Use Client Credentials for scheduled, app-only workflows: no sign-in, but you must create an application user in the environment with security roles.

Can the Dataverse node run inside an AI agent workflow?

Yes. The node shipped with a tool variant, so attach it as a tool in an AI Agent workflow, for example letting the agent look up a contact by GUID before drafting a reply.

What is the difference between Limit and Row Count ($Top) in Get Many?

Limit is the n8n-side cap; at 5,000 or less it is also sent to Dataverse as $top, and the node follows @odata.nextLink until the limit is reached. Row Count ($Top) is an explicit server-side cap that takes precedence and disables server-driven paging.

Why does my FetchXML query fail when Return All is on?

The node does not paginate FetchXML, so pairing a FetchXML query with Return All errors out. Turn Return All off and cap rows with Limit; use an OData query for automatic pagination.

Do I still need a community Dataverse node?

No. The built-in node covers create, read, update, upsert, and delete on standard and custom tables. Older community nodes remain useful only for niche extras like read-only SQL over the TDS endpoint.

TP
ToolPilot Team

We install, break, and fix automation tools so you don't have to. Every tutorial on ToolPilot is tested hands-on before publishing.

Keep reading