Idempotency in Dynamics 365 integrations
Why integrations must be idempotent — patterns for safe retries, deduplication, correlation IDs, and the design principles that prevent duplicates and inconsistencies.
In any distributed system, messages can be delivered more than once. A network timeout, a webhook retry, a Service Bus redelivery — all produce the same business event arriving twice. An integration that's not idempotent processes the message twice, creating duplicate records, double-charging customers, or sending repeated notifications. Designing for idempotency from the start is fundamental.
The problem.
A naive integration:
- External system sends "Customer X placed Order Y" event.
- Network glitch; the publisher retries.
- The consumer receives the event twice.
- The consumer creates Order Y twice in Dataverse.
- Customer X has two orders for one purchase; chaos.
Idempotency means: running the same operation twice produces the same result as running it once.
Patterns for idempotent operations.
1. Check before create. Before inserting a record, query for it:
Does Order Y exist?
Yes → already processed; do nothing.
No → create Order Y.
This works but has a race condition: two simultaneous executions could both find "doesn't exist" and both insert. Acceptable for low-volume scenarios with reasonable network conditions; insufficient for high-volume / mission-critical.
2. Upsert with alternate key. Use Dataverse's Upsert operation with an alternate key:
PATCH /api/data/v9.2/salesorders(ordernumber='Y')
{ ...order data... }
If the order exists, it's updated; if not, it's created. The platform handles the atomicity. Idempotent by design.
3. Correlation ID. Each external event carries a unique identifier (the event's ID, a UUID, a deduplication token). The consumer:
- Receives the event with correlation ID
evt-123. - Checks "have I processed event
evt-123before?" against a tracking store (Dataverse table, Azure Cache, or message header). - If yes, skip.
- If no, process and record
evt-123as processed.
This handles cases where the business operation isn't naturally identifiable by a stable business key.
4. Idempotency tokens. Some patterns send an explicit idempotency token in the request header. The consumer treats requests with the same token as duplicates of each other.
5. Natural keys. Many business entities have natural keys — order number, invoice number, transaction reference. If the publisher uses these consistently and the consumer matches by them, duplicates are detected naturally.
Dataverse-specific patterns.
Upsert. As mentioned, Dataverse's Upsert is the canonical pattern:
PATCH /api/data/v9.2/salesorders(ordernumber='ORD-2026-001')
Headers: If-Match: *
{
"orderdate": "2026-01-15",
"customerid_account@odata.bind": "/accounts(<GUID>)",
...
}
With an alternate key on ordernumber, the operation is idempotent regardless of how many times it's called with the same data.
ETag-based concurrency. Beyond idempotency, ETag-based optimistic concurrency prevents lost updates:
- Read the record; get its ETag.
- Submit the update with
If-Match: <etag>. - If the record changed between read and write, the update fails; consumer re-reads and retries.
Different from idempotency but complementary.
Service Bus deduplication. Azure Service Bus supports message deduplication — messages with the same MessageId within a deduplication window are treated as duplicates and discarded automatically. Set the MessageId to the business event's correlation ID; Service Bus handles the deduplication infrastructure.
Webhooks. Dataverse webhooks include a Cloud Event ID header — a unique ID per event firing. Consumers track which IDs have been processed; duplicates are detected.
Power Automate flows.
- Native trigger deduplication isn't always supported; check per trigger.
- Explicit deduplication step — use a Dataverse table to track processed correlation IDs; the flow checks before processing.
- Idempotent action choice — prefer Upsert over Create when possible.
Plug-ins.
Synchronous plug-ins running in the originating transaction inherit transactional idempotency — if the transaction fails, all effects roll back, including the plug-in's. Asynchronous plug-ins may retry; design them as idempotent or accept duplicates.
Compensation actions. When idempotency isn't possible (e.g. notification sending, payment processing), use compensation:
- Track every action with status.
- On detection of duplicate processing, compensate (reverse the duplicate effect).
Compensation is complex; design carefully.
Why this matters.
- Distributed systems aren't reliable — messages duplicate. Idempotency is the only sane design pattern.
- Retries are inevitable — clients retry on timeouts; queues redeliver; webhooks retry.
- Without idempotency, every retry is a bug waiting to happen.
Common pitfalls.
- Assuming "won't happen" — duplicates happen far more often than developers expect.
- No correlation ID — can't detect duplicates after the fact.
- Check-before-create with race conditions — works at low volume; fails at scale.
- Side effects without idempotency consideration — duplicate notifications, double-charges, repeated webhooks downstream.
Operational reality. Design every Dynamics 365 integration as idempotent. The investment is small; the cost of not doing it is dramatic when problems occur. Use Upsert, use correlation IDs, use natural keys; track processed events; expect retries.
Related guides
- Eventually consistent integrations with Dynamics 365How to design and operate eventually-consistent integrations — consistency vs availability trade-offs, conflict resolution, and the UX implications.
- Anti-corruption layers for Dynamics 365 integrationsHow anti-corruption layers protect Dynamics 365 from external system model leakage — translation patterns, when to apply ACL, and the maintenance discipline.
- API Gateway patterns for Dynamics 365How API gateways enhance Dynamics 365 integration architecture — Azure API Management, security, rate limiting, transformation, and the patterns for managed API surfaces.
- CQRS pattern for Dynamics 365How CQRS (Command Query Responsibility Segregation) applies to Dynamics 365 architectures — write vs read separation, projection patterns, and when CQRS helps vs hurts.
- Event-driven architecture for Dynamics 365How to design event-driven integrations around Dynamics 365 — event sources, brokers, consumers, and the patterns that produce loosely coupled, scalable architectures.