A property enquiry loses most of its value in the first hour. The client was collecting enquiries from listing portals, paid campaigns, its own website and site walk-ins, and routing them through inboxes and spreadsheets that added a day before an agent saw anything. ELIVTECH built an ingestion and routing layer on Laravel that deduplicates across every source, scores intent, and synchronises bi-directionally with Salesforce so the agent's own system stays authoritative.
The client develops and sells residential property across several projects, generating enquiries through listing portals, paid campaigns, its website and physical site visits. Each source arrived in a different format at a different destination, so the same person enquiring twice became two records competing for attention from two agents. Response times were measured in days because assignment was manual. Salesforce was in use but populated by periodic imports, which left it accurate only immediately after each one. ELIVTECH built a Laravel ingestion layer that normalises and deduplicates every source, scores leads on declared intent and observed behaviour, assigns them by configurable rules, and keeps Salesforce synchronised in both directions with conflict handling that does not overwrite agent work.
At a glance
The challenge
Enquiries arriving from everywhere, reaching agents late, and counted more than once.
Nine sources, nine destinations
Portal enquiries arrived by email, campaign leads landed in platform dashboards, website forms went to a shared inbox and walk-ins were written on paper. Each source had its own format and its own handler, so there was no single place where the day's enquiries existed and no way to measure the pipeline as a whole.
The same buyer counted several times
A person who enquired on a portal, clicked a campaign and later visited a site became three records. Different agents contacted them separately, the buyer received duplicate calls about the same property, and campaign performance was measured against a lead count that overstated genuine demand.
Assignment performed by hand
Somebody read each enquiry, decided which agent should take it and forwarded it on. That step ran during office hours only, so enquiries arriving in the evening or at a weekend waited until the next working morning, by which time the buyer had usually contacted someone else.
Salesforce accurate only after an import
Leads reached Salesforce through periodic file imports. Agent updates made in Salesforce never travelled back, so the two systems diverged continuously and staff learned to check both. The CRM held the relationship history while the operational reality lived somewhere else.
No way to tell strong leads from weak
Every enquiry looked identical in a list. A buyer who had specified budget, configuration and timeline sat alongside a casual browser with no distinguishing signal, so agents worked in arrival order and the most promising enquiries received attention at the same pace as everything else.
Campaign spend evaluated on bad data
Because sources were counted separately and duplicates were not removed, cost per lead was calculated against inflated numbers. Marketing decisions about where to invest were made on figures that neither reflected unique buyers nor connected to which enquiries eventually progressed.
Our solution
One ingestion layer, one identity per buyer, and a sync that respects who owns which field.
Source Mapping and Identity Design
Four weeks cataloguing every lead source, its format, its delivery mechanism and its reliability, alongside the rules that determine when two enquiries represent the same person. Phone number proved the strongest identity signal, with email and name similarity as supporting evidence. Those rules were written down and agreed before any code, because a deduplication policy applied silently is one nobody trusts.
Laravel Ingestion and Deduplication
Each source has an adapter that normalises its payload into one lead model, whether it arrives by webhook, API poll, parsed email or the site-visit application used on tablets. Incoming enquiries are matched against existing records using Elasticsearch fuzzy matching on the identity fields, and a match becomes a new interaction on the existing lead rather than a duplicate record. Borderline matches are held for review instead of being merged automatically, because joining two genuinely different buyers is far harder to undo than leaving two records to be merged later.
Scoring and Rule-Based Assignment
Leads are scored on declared intent such as budget, configuration and timeline, combined with observed behaviour including pages viewed and repeat enquiries. Assignment rules consider project, language, agent availability and current workload, distributing on a round-robin within each eligible group. Unacknowledged leads escalate automatically rather than waiting quietly in a queue, first to a second agent in the same group and then to a manager, with each step recorded against the lead.
Bi-Directional Salesforce Synchronisation
Field ownership is declared explicitly: the platform owns source, score and attribution, while Salesforce owns stage, agent notes and outcome. Changes flow both ways through queued jobs with retry and a dead-letter path, and each record carries a sync state so a failure is visible rather than silent. Agent work in Salesforce is never overwritten by a later platform update. A nightly reconciliation compares both systems and reports divergence rather than silently correcting it, so a systemic sync problem surfaces as a report instead of as quietly wrong data.
Technology stack
Results
Measured once every source was flowing through the platform and Salesforce sync was live.
Before and after: platform engineering measures
- Nine lead sources arriving in nine formats at nine destinations
- The same buyer recorded separately by each source
- Assignment performed manually during office hours only
- Salesforce populated by periodic one-way imports
- Agent updates in Salesforce never reaching the platform
- No scoring signal to distinguish intent
- Cost per lead calculated against duplicated counts
- Every source normalised through an adapter into one lead model
- Fuzzy identity matching folds repeat enquiries into one record
- Rule-based round-robin assignment running continuously
- Bi-directional sync with explicit field ownership
- Sync state visible per record, failures surfaced not swallowed
- Leads scored on declared intent and observed behaviour
- Attribution measured against unique buyers through to outcome
Project timeline
Source Mapping and Identity Design
Catalogue of every lead source and delivery mechanism, deduplication rule definition and sign-off, Salesforce object and field ownership agreement, and the target Laravel ingestion architecture.
Ingestion and Deduplication
Adapter per source across webhook, API poll, parsed email and tablet capture, normalised lead model in MySQL, Elasticsearch identity matching, interaction history on merged records, and the AWS deployment pipeline.
Scoring, Routing and Agent Tools
Scoring model on declared and behavioural signals, assignment rules by project, language, availability and workload, escalation on unacknowledged leads, and the agent working view with full interaction history.
Salesforce Synchronisation
Bi-directional sync with declared field ownership, queued jobs with retry and dead-letter handling, per-record sync state, conflict resolution favouring agent-owned fields, and reconciliation reporting between systems.
Attribution, Consent and Rollout
Attribution reporting from source through to outcome, consent capture and retention policy for enquiry data, monitoring on ingestion lag and sync failures, then source-by-source cutover with legacy inboxes retained during transition.
Key takeaways
What shaped the engineering decisions
- Agree the deduplication rules in writing first: Merging silently on a heuristic destroys trust the first time it merges two genuinely different buyers. Documenting and signing off the identity rules meant agents understood what the system would and would not join.
- Declare field ownership before building sync: Bi-directional synchronisation without an ownership model is a race. Naming which system owns each field turned conflict resolution into a lookup instead of a judgement made at runtime.
- Normalise at the adapter, not downstream: Handling source-specific quirks inside each adapter keeps scoring, routing and reporting working on one shape. Adding a tenth source is writing an adapter, not amending the pipeline.
- Make sync failures visible: Silent retries hide a divergence until someone notices the numbers disagree. Per-record sync state with a dead-letter path means a stuck record is a monitored condition rather than a discovery.
- Escalate on silence, not only on rejection: A lead nobody declines but nobody contacts is the common failure. Escalating unacknowledged assignments closed the gap that manual routing used to hide.
- Handle consent at ingestion: Enquiry data carries consent and retention obligations that vary by source. Capturing consent state at the point of ingestion, and enforcing retention from it, kept the obligation with the record rather than in a policy document.
Want results like these?
Let's discuss how ELIVTECH can drive measurable outcomes for your business.
Start your project