Skip to main content
Funding Machine’s default for a CRM Location’s Contact Deduplication Preferences is:
  • Allow Duplicate Contact: off
  • Find existing contacts based on: Phone
  • Second preference for search: None
In the CRM’s Location settings these are allowDuplicateContact: false and contactUniqueIdentifiers: ["phone"]. From 2026-10-07 (PR #1890) first installations turned Allow Duplicate Contact on instead; that changed on 2026-10-14. Setup preserves every other Location setting, including Allow Duplicate Opportunity. Sticky Contact forms can still reuse a Contact on a shared browser; see the CRM’s Sticky Contact guidance.

First installations

Setup requires a verified marketplace INSTALL notification and the Location’s credentials. Either may arrive first. A first OAuth authorization can wait for the notification; lazy credential discovery during an app open cannot start this setup. Existing installation history excludes older accounts, even after uninstall or credential cleanup. Successful setup records verification once. Later app opens, token refreshes, reauthorization, duplicate notifications and reinstalls do not reapply it. Uninstall cancels pending work. Setup still pending from before 2026-10-14 (which would have turned duplicates on) is cancelled when it next runs and writes nothing; the batch below covers those Locations. The setup reads current settings, sends companyId plus all returned settings with the default applied, then reads again. A successful PUT without confirmed readback is not configured. Before the first PUT, setup keeps the original settings in installation history (settingsBeforeWriteJson); retries must confirm those other settings. A mismatch stays a visible failure until staff reconcile it in the CRM.

Installed Locations

Run scripts/contact-deduplication-batch.ts with an admin session (FM_ADMIN_SESSION_TOKEN) and a Convex CLI login to production. This applies the default everywhere, including Locations where the Operator chose otherwise.
  1. Pilot one Location first: run with --locations <id>, apply it, and check that Location’s Contact settings in the CRM.
  2. Run without --apply. It is read only: it checks every installed Location and writes contact-deduplication-report/check-<time>.json, listing each as default, differs (with its current values) or unavailable (with the reason).
  3. Review that report. Only differs Locations will change.
  4. Run again with --apply <that report>. For each differs Location the server reads the settings again, sends them back with only the two deduplication settings changed, and reads once more to verify. Results go to contact-deduplication-report/apply-<time>.json.
Only admins can apply: the endpoint requires an admin session and Convex checks the admin again before writing. The Location must still be installed under the same agency right before the write. Every apply is recorded in the contactDeduplicationChanges table: a started row with the two settings it replaces (beforeJson), saved before the write, then the outcome with the admin and time. So any Location can be put back, even if the CRM’s response was lost. Re-running is safe. If your admin session expires mid-run, the report still lists every Location, with the ones not reached marked not_run. Unavailable means the owning agency hasn’t authorized locations.readonly and locations.write, or the Location is no longer installed. Reconnect the owning agency and re-run, or change the setting by hand in that Location’s CRM Contact settings. Failed means the CRM didn’t confirm the change or another setting changed at the same time; check that Location by hand.

Permissions

The official scope table requires agency access and locations.write for PUT /locations/. Reading settings also requires locations.readonly. A Location token cannot substitute for the owning agency’s token. Requests use the pinned SDK’s locations.getLocation and locations.putLocation with that agency token.

Verify and recover

Open Admin → Locations. Under the Location name, Contact deduplication setup verified means the first-install setup confirmed the default by readback. It records installation verification, not a live monitor of later changes. Duplicate Contact turned on at install (before Oct 14); apply the new default marks a Location whose earlier setup turned duplicates on; the batch applies the default there. Contact deduplication setup needs attention; retry scheduled includes the failure and required action. Missing agency authorization or scope requires a maintainer to correct marketplace permissions and reconnect the owning agency. Do not mark setup complete manually or change another Location to work around the error. Recovery retries after one minute, five minutes, 15 minutes and one hour, then every six hours. Each attempt reads current settings first, so a write whose response was lost is confirmed without another PUT. Concurrent attempts use one durable claim; an interrupted attempt is recovered after five minutes. Failure details never include credentials or provider request objects.