Connecting Microsoft Dynamics 365 — CRM sync via Azure AD

The Dynamics 365 connector mirrors your Dynamics 365 Accounts, Contacts, and Opportunities into Turtini's CRM. Authentication is OAuth 2.0 against Microsoft Entra ID (Azure AD), so the credentials your org's IT team already manages are reused.

Step 1 — Register an app in Azure AD (your IT team or tenant admin):
1. portal.azure.com → Microsoft Entra ID → App registrations → New registration
2. Name it ("Turtini Dynamics Sync"), supported account types = single tenant
3. Set the Redirect URI to `https://{your-turtini-domain}/oauth-callback.html` (web platform)
4. Save. On the app's overview, copy the Tenant ID and Application (client) ID
5. Certificates & secrets → New client secret → 24-month expiry → copy the secret value (it's only shown once)
6. API permissions → Add → Dynamics CRM → Delegated → `user_impersonation` → Grant admin consent

Step 2 — Find your Dynamics environment URL:
In Dynamics, this is the URL of your environment (e.g. `https://yourorg.crm.dynamics.com` for US, `.crm4.dynamics.com` for EMEA, etc.). This is the Resource URL Turtini will request a token against.

Step 3 — Connect in Turtini:
1. Settings → Integrations → Dynamics 365 card
2. Paste Tenant ID, Client ID, Client Secret, Resource URL
3. Save credentials — they land in your org's Secret Manager entry
4. Click "Connect" — a Microsoft sign-in popup opens at `login.microsoftonline.com`
5. Sign in with the user account whose access the connector should use
6. Approve the consent screen
7. The popup closes and the connection activates — you'll see the Resource URL and last-sync timestamp

What mirrors over:
• Dynamics Accounts → `accounts` (name, primary contact, address, industry, revenue)
• Dynamics Contacts → `contacts` (name, email, phone, job title, parent account)
• Dynamics Opportunities → `opportunities` (name, amount, estimated close date, sales stage, parent account, sales process status)

Standard fields only — custom entities and custom fields aren't synced in Phase 1.

Sync cadence:
• Daily scheduled sync (`syncDynamicsConnections`) pulls everything modified since the last run via the Dataverse Web API
• "Sync now" button on the card runs the same sync on demand
• Sync is keyed on the Dynamics record GUID — idempotent

Sync scope toggles:
Each of the three object types has a checkbox. Defaults are all on; toggle off on the integration card to skip an object type on the next run.

Token refresh:
Turtini stores the refresh token in your org's Secret Manager entry; access tokens are short-lived and auto-refreshed during sync. If the refresh token expires (typically 90 days of inactivity or if the user's password changes in Entra ID), the card will surface "Reconnect" — click it to re-run the OAuth popup with the same Azure AD app credentials.

Multi-environment notes:
If your org runs separate Dynamics environments for production and UAT, you have two options:
• Connect once with the production Resource URL — preferred for most orgs
• Run two Turtini orgs (or use a Test workspace) — currently one Dynamics connection per Turtini org

Disconnect: the card has a "Disconnect" button that clears the stored refresh token. Mirrored records stay in Turtini with their Dynamics GUIDs intact so you can reconnect without losing the link.

If something fails:
• "AADSTS500113: No reply address is registered" — the Redirect URI in Azure AD doesn't match the one Turtini sent. Make sure it's exactly `{turtini-domain}/oauth-callback.html`.
• "AADSTS65001: The user or administrator has not consented" — Grant admin consent on the API permission in Azure AD.
• "401 Unauthorized" during sync — the connected user has lost access to the Dynamics environment or to the `user_impersonation` permission; check Entra ID assignments.