Integration

When a Dynamics 365 write times out, prove what happened before you retry

Suppose an external system sends a new customer to Dynamics 365 Sales, but its response never arrives. Support must establish whether the customer exists and whether replaying the request would repeat other work.

Updated · AI disclosure

The integration needs to provide:

  • One stable identity for the customer across attempts
  • A way to distinguish failed work from an unknown outcome
  • Retry rules that respect the service and the operation
  • Evidence that support can use to resolve exceptions

Microsoft's retry guidance describes this failure mode: a service can process a request successfully and then fail to return the response. A timeout therefore leaves the outcome uncertain.

This example targets the standard Dataverse account table used by a Dynamics 365 Sales integration. Dynamics 365 Sales runs on Microsoft Dataverse. Other Dynamics 365 integrations require their own endpoint and transaction semantics to be checked.

Decide what the request is allowed to change

Start with one operation: create the customer account if it does not already exist. Updating an existing customer's details is a separate operation with its own ownership and conflict rules.

Give the source customer a stable, namespaced identifier, such as ERP-CUST-1042. Persist an operation ID, the target identity, and a fingerprint of the canonical request before sending. Redelivery must reuse that identity and payload; conflicting data under the same operation ID needs investigation.

In Dataverse, configure a custom text column named new_externalcustomerid as an alternate key and wait for its index status to become Active. Require a non-null identifier on every integration request: null key values do not enforce uniqueness. Check permitted key characters and resolve existing duplicates during setup. Alternate keys provide enforced row identity; the operation journal provides the history of attempts. They serve different purposes.

Make the create-only rule explicit

The HTTP example assumes the custom column and active key exist, the caller has appropriate account privileges, and required business fields are satisfied. Replace {org} with the authorized organization host and authenticate through the application's configured client.

HTTP example
PATCH https://{org}/api/data/v9.2/accounts(new_externalcustomerid='ERP-CUST-1042')
Content-Type: application/json
Accept: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0
If-None-Match: *

{
  "name": "Example Customer"
}

The alternate-key value belongs in the URL. A normal Dataverse PATCH upsert can create or update the matching row; If-None-Match: * prevents the update. With this request, a successful creation normally returns 204 No Content, while an existing matching row produces 412 Precondition Failed. These conditional semantics are documented.

That makes a repeated attempt converge on one customer identity without silently overwriting an existing account. It does not make 412 proof that this particular attempt succeeded.

Reconcile the uncertainty before declaring success

Persist InFlight before sending. After a timeout, mark the entry Unknown. On restart, reconcile stale InFlight entries too: the process may have crashed after Dataverse committed but before saving the response. Read the same identity before deciding to resend:

HTTP example
GET https://{org}/api/data/v9.2/accounts(new_externalcustomerid='ERP-CUST-1042')?$select=accountid,name,new_externalcustomerid
Accept: application/json
OData-Version: 4.0
OData-MaxVersion: 4.0

Define the response handling in advance:

  • If a row exists, compare the fields this operation owns. If mapping trims names, compare name with the trimmed source value. If Sales owns ownerid, exclude it from this check. A match confirms the desired customer state; save its accountid and reconciliation evidence.
  • An existing row with conflicting values goes to the responsible data owner. Do not turn the create request into an overwrite.
  • A missing row remains unresolved while the first request may still be running. Recheck with backoff or retry the same guarded create within the recovery policy.
  • A failed or inaccessible read leaves the outcome unknown. Do not label it absent.

Reconcile an existing-row 412 through the same path. Reading matching values establishes current state, not which attempt produced it. The request fingerprint detects conflicting operation-ID reuse; it does not prove stored state. Dataverse's upsert documentation explains how URL keys identify the target.

A customer row is only one part of completion

What if creating the account also starts a welcome message or an ERP onboarding process?

Dataverse extensions can run asynchronously outside the database transaction. A saved account therefore does not prove that every downstream step completed. The event framework documents this boundary.

Give consequential downstream operations their own stable operation identity, durable result, and reconciliation path. Where you control the consumer, enforce duplicate detection atomically with its local state change. External effects require the destination's own idempotency or lookup mechanism. If neither exists, route ambiguity for review before replaying it. The account key alone provides no end-to-end exactly-once guarantee.

Put retries within a bounded recovery process

For a Dataverse service-protection 429, honor the returned Retry-After delay. Microsoft documents that retry contract. Use bounded backoff for eligible transient failures, accounting for retries already performed by the client library. Authentication, validation, and business-rule failures need correction rather than an endless retry loop.

Keep unresolved operations in a durable exception queue with an owner and an agreed response deadline. Before release, exercise lost responses, concurrent duplicates, conflicting payloads, throttling, and downstream failure. Completion means each operation has confirmed evidence or an owned exception, with customer creation and downstream completion reported separately.

These HTTP examples are documentation-checked request shapes. They have not been executed against a Dataverse environment or its custom business logic.

Discuss your Dynamics 365 integration

Sources

Written with AI and not reviewed by a human. It may contain mistakes.