Skip to main content

Microsoft Dynamics 365 CRM ExecModule

Overview

MicrosoftDynamics365Module connects ValkyrAI workflows to the Microsoft Dataverse Web API v9.2 through the native map I/O ExecModule ABI. It creates, reads, lists, updates, and guarded-deletes accounts, contacts, leads, and opportunities without exposing OAuth credentials to workflow payloads.

The connector extends the useful account operations in n8n's Microsoft Dynamics CRM node across the four core sales entities. It validates one trusted organization origin, allowlists mutation and selection fields, bounds OData requests and responses, retries only reads, applies optional ETag concurrency checks, and requires explicit confirmation before deletion.

Usage

  1. Register a Microsoft Entra application or delegated identity for the target Dynamics environment.
  2. Grant only the Dynamics security-role privileges required for the selected entity operations.
  3. Store the OAuth access token in the encrypted IntegrationAccount.apiKey or password SecureField.
  4. Store the organization origin in IntegrationAccount.accountId, for example https://acme.crm.dynamics.com.
  5. Set the account to READY and bind it through ExecModuleConfig.authConfig.integrationAccount.
  6. Use list operations to discover UUIDs, then pass those UUIDs to get, update, or guarded-delete operations.

Workflow inputs cannot supply authorization headers, alternate hosts, client secrets, refresh tokens, or arbitrary Dataverse entity sets.

Inputs

NameTypeRequirementDefaultConstraints
operationstringRequiredNoneOne of the twenty operations below.
organizationUrlstringOptionalIntegrationAccount.accountIdHTTPS global Dynamics host such as https://acme.crm.dynamics.com; no path, port, query, credentials, or fragment.
recordIdstringGet, update, and deleteNoneCanonical Dataverse UUID; braces are normalized.
recordobject or JSONCreate and updateNoneNon-empty, at most 50 allowlisted scalar fields and 256 KiB.
selectstringOptional read projectionProvider default1–50 comma-separated allowlisted fields.
filterstringOptional list filterNoneBounded OData expression, at most 4,096 characters; nested $ options and unsupported characters are rejected.
orderBystringOptional list orderingProvider defaultOne allowlisted field plus optional asc or desc.
cursorstringOptional list continuationNoneOpaque $skiptoken returned as nextCursor, at most 4,096 characters.
limitintegerOptional1001–5,000 rows in one provider page.
etagstringOptional update/delete concurrencyNoneBounded strong or weak ETag sent as If-Match.
confirmDeletebooleanDelete operationsfalseMust be exactly true before a DELETE is sent.
timeoutMsintegerOptional30000100–300,000 ms for connect, read, write, and total call time.

Create requirements:

  • Accounts require name.
  • Contacts require lastname.
  • Leads require subject and lastname.
  • Opportunities require name.

Writable fields are intentionally narrower than the entire tenant schema. Common addresses, phone and email fields, descriptions, revenue/value fields, stage/status fields, and selected @odata.bind relationships are available. Server-owned UUIDs, fullname, createdon, and modifiedon are read-only. Unknown fields and nested objects or arrays fail validation before transport.

Outputs

NameTypeWhen presentDescription
statusstringAlwayssuccess or error.
operationstringAlwaysNormalized operation name.
resourcestringValid operationaccounts, contacts, leads, or opportunities.
attemptsintegerAlwaysProvider attempts consumed.
httpStatusintegerProvider responded successfullyLast HTTP status.
dataobjectSingle-resource or mutation successProvider representation or an accepted mutation receipt.
idstringProvider or request supplies identityCanonical Dataverse UUID.
items / countarray / integerList successBounded rows and emitted count.
hasMorebooleanList successWhether Dataverse returned another page.
nextCursorstringAnother page existsValidated opaque skip token.
errorobjectFailureSafe code, message, retryability, and attempt count.

OAuth tokens, authorization headers, and credential-like provider messages are redacted from outputs, logs, and workflow events.

IntegrationAccount Requirements

SettingRequirement
ProviderMicrosoft Dynamics 365 / Dataverse
accountNameHuman-readable automation identity
accountIdFull global Dynamics organization origin, for example https://acme.crm.dynamics.com
apiKey or passwordEncrypted SecureField containing the OAuth access token
statusExactly READY

The OAuth grant must target the Dynamics organization resource and the bound principal must have a Dynamics security role that authorizes each selected table and action. Token acquisition, refresh, consent, and role assignment remain IntegrationAccount lifecycle responsibilities. The module does not accept a client secret or refresh token in workflow data.

Configuration

{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:dynamics-sales-ops"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 5000
},
"executionConfig": {"timeoutMs": 30000},
"payloadConfig": {
"parameters": "{\"organizationUrl\":\"https://acme.crm.dynamics.com\",\"operation\":\"list_opportunities\",\"select\":\"opportunityid,name,estimatedvalue,estimatedclosedate\",\"filter\":\"statecode eq 0\",\"orderBy\":\"estimatedclosedate asc\",\"limit\":100}"
}
}

The account reference is symbolic. Persisted workflows bind the generated IntegrationAccount relationship, never plaintext credentials.

Operations

Operation familySupported resourcesBehaviorSide effect
list_<resource>accounts, contacts, leads, opportunitiesReturns one bounded OData page with optional selection, filter, ordering, and continuation.Read-only; safe retries.
get_<resource>account, contact, lead, opportunityReads one UUID-addressed row with an optional projection.Read-only; safe retries.
create_<resource>account, contact, lead, opportunityCreates one row from allowlisted fields and requests a representation.Mutation; one attempt.
update_<resource>account, contact, lead, opportunityPatches one row, optionally guarded by If-Match.Mutation; one attempt.
delete_<resource>account, contact, lead, opportunityDeletes or deactivates according to provider behavior after explicit confirmation.Destructive; one attempt.

The exact twenty operation names are list_accounts, get_account, create_account, update_account, delete_account, and the equivalent five operations for contacts, leads, and opportunities.

Errors and Failure Modes

CodeTypical causeRetryableResolution
VALIDATION_ERRORMissing UUID/create field, unsafe tenant, invalid field/JSON/ETag/filter/cursor/bound, empty mutation, or absent delete confirmation.NoCorrect the named input; no unsafe request was sent.
UNSUPPORTED_OPERATIONUnknown operation or entity family.NoSelect one of the twenty documented operations.
INTEGRATION_ACCOUNT_REQUIREDNo account is bound.NoBind a Microsoft Dynamics IntegrationAccount.
INTEGRATION_ACCOUNT_NOT_READYAccount is not exactly READY.NoRepair or reconnect the account.
DYNAMICS_HTTP_400Invalid field, OData expression, relationship binding, or provider constraint.NoCorrect the bounded request using tenant metadata.
DYNAMICS_HTTP_401Access token is missing, expired, revoked, or issued for the wrong resource.NoRefresh the IntegrationAccount OAuth grant.
DYNAMICS_HTTP_403Dynamics security role lacks table or action privilege.NoGrant only the missing least-privilege permission.
DYNAMICS_HTTP_404UUID is wrong, deleted, or invisible.NoRe-run discovery under the same principal.
DYNAMICS_HTTP_412ETag does not match the current row.NoRead the current row, reconcile changes, and retry intentionally.
DYNAMICS_HTTP_429Dataverse service-protection limit is exhausted.Yes for readsHonor Retry-After and reduce concurrency.
DYNAMICS_HTTP_5xxTransient provider failure.Yes for readsRetry reads; reconcile writes before manual replay.
NETWORK_ERRORTimeout, DNS, TLS, or connectivity failure.Yes for readsVerify connectivity; inspect Dynamics before repeating a write.
RESPONSE_TOO_LARGEResponse exceeded 5 MiB.NoLower limit or narrow select and filter.
EXECUTION_ERRORAn unexpected local normalization failure occurred.NoInspect sanitized logs and provider compatibility.

Example

Create an opportunity after a governed workflow validates the account and commercial terms:

{
"operation": "create_opportunity",
"record": {
"name": "Enterprise platform renewal",
"description": "Verified expansion opportunity from Q3 account review.",
"estimatedvalue": 25000,
"estimatedclosedate": "2026-09-30",
"closeprobability": 70,
"customerid_account@odata.bind": "/accounts(11111111-1111-4111-8111-111111111111)"
}
}

Expected result:

{
"status": "success",
"operation": "create_opportunity",
"resource": "opportunities",
"attempts": 1,
"httpStatus": 201,
"id": "33333333-3333-4333-8333-333333333333",
"data": {
"opportunityid": "33333333-3333-4333-8333-333333333333",
"name": "Enterprise platform renewal",
"estimatedvalue": 25000
}
}

Notes

  • Pagination: Dataverse list operations request at most 5,000 rows and expose only a validated $skiptoken from a trusted @odata.nextLink. Feed nextCursor back as cursor; do not construct or edit it.
  • Rate limits: HTTP 408, 429, 500, 502, 503, and 504 and network failures may retry for GET operations, honoring numeric Retry-After within a five-second local bound. Writes never retry automatically.
  • API limits: request JSON is capped at 256 KiB, list output at 5,000 rows per page, and every response at 5 MiB. Selection and filtering should be as narrow as the workflow permits.
  • Idempotency: reads are repeatable for a fixed provider state. Create, update, and delete are single-attempt because a timeout can follow a committed mutation. Reconcile by UUID or business key before replaying a write.
  • Concurrency: pass the current row ETag for update or delete when lost-update protection matters. A 412 is a reconciliation signal, not a retry signal.
  • Destructive behavior: every delete requires confirmDelete=true. Dynamics cascading, auditing, deactivation, retention, recycle-bin, and plugin behavior is tenant-configured; review those rules before enabling delete operations.
  • API behavior: synchronous Dynamics plugins, Power Automate flows, business rules, duplicate detection, auditing, notifications, and downstream integrations can run as side effects of a mutation.
  • Authentication: this release supports global commercial Dynamics hosts matching *.crmN.dynamics.com. Government and China clouds are deferred until their authority and host contracts are modeled explicitly.
  • External verification: deterministic local tests cover OAuth headers, trusted routing, account/contact/lead/opportunity paths, bounded OData, pagination, allowlists, UUID identity, ETags, safe-read retry, single-attempt writes, delete confirmation, redaction, and metadata discovery. Live tenant roles, plugins, service-protection quotas, and custom columns require separately authorized Dynamics credentials and are not exercised in repository tests.
  • Deferred operations: custom tables/columns, metadata discovery, FetchXML, alternate keys, upsert, batch and change sets, file/image columns, notes and activities, lead qualification, opportunity close/reopen actions, duplicate detection controls, relationship management beyond the exposed bindings, webhooks, and triggers are deferred.
  • Functional references: n8n Microsoft Dynamics CRM node and Microsoft Dataverse Web API.