Here’s a complete solution addressing all aspects of your territory sync issue:
Duplicate Key Handling:
Define an alternate key on the territory member entity combining systemuserid and territoryid. In Power Apps, go to Settings > Customizations > Entities > Territory > Keys, and create a new alternate key. This enables upsert operations:
PATCH /api/data/v9.1/territories(userid='guid',territoryid='guid')
Content-Type: application/json
{"_systemuserid_value": "user-guid", "_territoryid_value": "territory-guid"}
Upsert Logic Implementation:
Replace your POST-only approach with PATCH requests using alternate keys. The API automatically creates if the record doesn’t exist or updates if it does. This eliminates duplicate key violations entirely.
For bulk operations, use $batch requests to maintain transactional consistency across multiple territory assignments.
Data Reconciliation Strategy:
Implement a three-phase sync process:
-
Discovery Phase: Query existing territory assignments for all users in the HR sync batch. Build a lookup dictionary mapping user+territory combinations to record IDs.
-
Comparison Phase: Compare HR data against CRM data to identify three categories: assignments to create (in HR, not in CRM), assignments to remove (in CRM, not in HR), and assignments to update (in both, but with changed attributes).
-
Execution Phase: Process in order - DELETE obsolete assignments first, then PATCH/create new assignments. This ordering prevents constraint violations.
HR-CRM Integration Best Practices:
Add a sync tracking field (hr_lastsyncdate) to territory member records. During each sync, update this timestamp. Records with old timestamps indicate orphaned assignments that should be reviewed.
Implement change tracking in your HR system to send only delta changes rather than full snapshots. This reduces processing time and minimizes conflict opportunities.
Use the RetrieveMultiple API with FetchXML to efficiently query existing assignments:
GET /api/data/v9.1/territories?fetchXml=<fetch>
<entity name='territory'>
<filter><condition attribute='systemuserid' operator='in'>
<value>{user-guid-1}</value>
</condition></filter>
</entity>
</fetch>
Add error handling with automatic retry for transient failures. Log all sync operations to a staging table before committing to CRM, allowing you to rollback or replay failed syncs.
Implement a validation webhook that fires when territory assignments change, comparing against HR system as source of truth. This catches manual changes that might conflict with automated syncs.
Finally, schedule your HR sync during low-activity periods and implement a locking mechanism to prevent concurrent syncs from causing race conditions.
This draft is based on general Microsoft Dynamics 365 Sales knowledge. It has not been verified against your specific version and environment. Practitioners: verify the steps and share your experience below.