CRM Sync That Doesn't Break

CRM Sync That Doesn't Break

When you build and operate a CRM integration product, you learn things that client projects rarely teach you. With LeadCall, we push phone call records into Zoho, HubSpot, Salesforce, and Pipedrive on behalf of sales teams. Here is what running that in production for years has taught us about CRM sync that actually holds together.

Rate Limits Are Not a Corner Case

Every CRM has them. Zoho allows around 150 API requests per minute per organisation. HubSpot's limit is per 10-second window. Salesforce is plan-dependent and resets in ways that require you to read their API response headers, not maintain a local counter. The first mistake teams make is treating rate limits as something to handle when they hit them. We build around them from day one — a token bucket per integration per tenant, drained by an async queue. When the bucket is empty, writes wait. Nothing is dropped.

Deduplication Is the Real Problem

Every CRM sync needs to answer one question before writing: does this record already exist? For LeadCall, we match on phone number — but phone numbers arrive from mobile apps in every format imaginable: +44 7911 123456, 07911123456, 07911 123 456, 44-7911-123456. We normalise everything to E.164 on ingest. Even then, the CRM may have the same number stored in a different format from before our integration existed. So we normalise on both sides before comparing.

We also deduplicate write attempts using idempotency keys composed of (tenant_id, call_id, crm_type). The same call cannot create two CRM records, even if the job is processed twice due to a worker crash and retry.

What Happens When the CRM Changes Externally

A contact gets renamed in Salesforce by the sales manager. A deal stage gets changed by a colleague. Our sync doesn't know. We don't overwrite CRM changes made outside our integration — we log what we pushed and when, and only reconcile fields we explicitly own. CRM integrations that blindly overwrite are a nightmare for sales teams who rely on those systems daily. We define a clear field-ownership contract per integration and document it before writing a line of sync code.

Audit Logging Is Not Optional

Every sync operation writes a structured log entry: what was pushed, when, to which CRM, what the CRM returned, and whether it succeeded or is pending retry. This isn't primarily for debugging — it's for support. When a sales manager says 'why didn't my call show up in HubSpot,' we can answer within 30 seconds by searching the audit log by call ID.

Dead Letter Queues Keep the System Honest

Retries with exponential backoff handle transient CRM API errors — 429s, 503s, network timeouts. But some failures are not transient: the contact was deleted, the custom field was removed, permissions changed. These go to a dead letter queue with a tagged reason. They don't vanish silently and they don't cause infinite retries. They get alerted on, reviewed, and either resolved by configuration or acknowledged as expected.

The mark of a reliable integration is not that it never fails — it's that every failure is visible, categorised, and accounted for.

/ Mohammad Hammoud

More on topic

Photography
3D Models
Development
Illustrations
Fashion
Digital Art
Packaging
Motion
Illustrations
Video Production
Photography
3D Models
Development
Illustrations
Fashion