Salesforce duplicating contact records on sync

FieldPulse version: 3.2.1
Salesforce integration version: 1.4.2
Environment: Production

I have confirmed that the Salesforce integration is creating duplicate Contact records during the bidirectional sync. I can reproduce this when:

  1. A customer exists in FieldPulse with email john.smith@example.com
  2. A Contact exists in Salesforce with the same email address but different capitalization (John.Smith@example.com)
  3. The sync runs and creates a second Contact in Salesforce rather than matching to the existing record

I have verified that the Email field in Salesforce is marked as unique at the object level, but the matching appears to be case-sensitive. The duplicate detection in FieldPulse settings is configured with "Email (Exact Match)" enabled.

From a governance perspective, I need to understand whether the matching logic is configurable or if this requires a custom Salesforce duplicate rule. I have confirmed that approximately 340 duplicate Contacts have been created in the past 30 days.

Is this expected behavior, or is there a configuration option I have overlooked? I have reviewed Connecting FieldPulse to Salesforce and the field mapping documentation but did not locate guidance on matching criteria.

Parents
  • Rachel, thanks for the detailed repro steps — that case-sensitivity behavior is definitely not ideal, and yeah this one tripped me up too when I first looked at it. The connector currently does a literal string comparison on the email field before deciding whether to update or create.

    Devon's approach with Salesforce Duplicate Rules is solid and will prevent the duplicates from persisting, but I want to flag that we're tracking this as a known limitation. The matching logic should normalize emails before comparison, and I've bumped the priority on the internal ticket.

    For immediate mitigation, here are the two paths:

    Option 1: Salesforce-side (Devon's suggestion, recommended)

    // Example Flow: Before-Save on Contact
    // Formula: LOWER(Email)

    Plus a Duplicate Rule with fuzzy matching as described.

    Option 2: FieldPulse-side data cleanup

    Export your customer list, normalize emails to lowercase via spreadsheet or script, then re-import using the bulk update endpoint. I know, not elegant — but it prevents the root cause from your end.

    There's also a workaround doc that covers this: Salesforce Integration Not Updating Opportunity Status — different symptom, same underlying matching quirk.

    I'll update this thread when the normalize-on-compare fix ships. Tentatively targeting 3.3 but don't quote me on that.

  • Good question — there's no bulk PATCH, so you'd need to loop with PUT /customers/{id}. Rate limit is 100 req/min, so for 340 records you're looking at ~4 minutes with basic backoff.

    Quick snippet if you're scripting this:

    const customers = await fetchCustomersWithEmails(); // your export
    for (const c of customers) {
      await fetch(`api.fieldpulse.io/.../${c.id}`, {
        method: 'PUT',
        headers: { 'Authorization': 'Bearer TOKEN', 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: c.email.toLowerCase() })
      });
      await sleep(600); // ~100/min
    }

    The customer_id is preserved — PUT only updates the fields you send.

Reply
  • Good question — there's no bulk PATCH, so you'd need to loop with PUT /customers/{id}. Rate limit is 100 req/min, so for 340 records you're looking at ~4 minutes with basic backoff.

    Quick snippet if you're scripting this:

    const customers = await fetchCustomersWithEmails(); // your export
    for (const c of customers) {
      await fetch(`api.fieldpulse.io/.../${c.id}`, {
        method: 'PUT',
        headers: { 'Authorization': 'Bearer TOKEN', 'Content-Type': 'application/json' },
        body: JSON.stringify({ email: c.email.toLowerCase() })
      });
      await sleep(600); // ~100/min
    }

    The customer_id is preserved — PUT only updates the fields you send.

Children
No Data