Skip to content

Lead Source Driver Architecture

Status: Implemented

Shared lead ingestion pipeline with LeadSourceDriverInterface, NormalizedLeadData, LeadDuplicateService, and LeadIngestionService. Shipped drivers: Custom Webhook and Meta Lead Ads. Additional catalog drivers remain planned.


Purpose

Every external lead source must pass through a Lead Source Driver before reaching the Lead module.

The Lead module must never contain source-specific parsing logic (Meta field maps, CSV column quirks, WhatsApp payload shapes, form-plugin schemas, CRM export formats, and so on).

LayerOwns
DriverAuthentication, receiving data, validation, normalization into a common shape
Lead moduleDuplicate detection, creation, assignment, activities, notifications, automations, timeline, business rules

Business logic remains centralized inside the Lead module. Drivers are adapters at the edge.


LeadSourceDriverInterface

Proposed architectural contract. Actual method names may change during implementation — these responsibilities define the contract, not a finalized PHP API.

ResponsibilityIntent
authenticate()Establish or verify credentials / connection context for the source
validate()Reject malformed or unauthorized inbound payloads before normalization
normalize()Map source-specific data into NormalizedLeadData
import()Hand normalized data into the shared ingestion pipeline (never direct DB writes)
supportsWebhook()Whether this driver accepts push ingress (webhooks)
supportsPolling()Whether this driver may pull / poll the external system

Drivers that only support one ingress mode return the appropriate capability flags. Shared infrastructure (webhook router, polling scheduler) consults these capabilities rather than hard-coding source names in the Lead module.


Ingestion pipeline

Every lead — regardless of origin — follows the same pipeline after the driver produces normalized data:

text
Incoming Lead Source

Lead Source Driver

NormalizedLeadData DTO

LeadDuplicateService

LeadService

LeadActivityService

LeadAssignmentService

Notification System

Automation Engine

Timeline

Non-negotiable rules

  • No driver may bypass this pipeline.
  • No driver may insert records directly into the database.
  • All lead creation must pass through LeadService.

Duplicate detection, assignment, activity logging, notifications, and automations are Lead-module (or platform) concerns invoked after normalization — not inside the driver.

Sequence (conceptual)

mermaid
sequenceDiagram
  participant Src as External Source
  participant Drv as Lead Source Driver
  participant DTO as NormalizedLeadData
  participant Dup as LeadDuplicateService
  participant LS as LeadService
  participant Act as LeadActivityService
  participant Asn as LeadAssignmentService
  participant N as Notifications / Automations
  participant TL as Timeline

  Src->>Drv: Webhook / poll / upload / API
  Drv->>Drv: authenticate + validate
  Drv->>DTO: normalize()
  Drv->>Dup: import() enters shared pipeline
  Dup-->>LS: create | update | skip
  LS->>Act: activity events
  LS->>Asn: assignment rules
  LS->>N: notification + automation hooks
  LS->>TL: timeline entries

Service names such as LeadActivityService and LeadAssignmentService describe ownership boundaries. Implementation may map them to existing classes (LeadService methods, event subscribers, assignment helpers) as long as drivers never own those concerns.


Future driver catalog

Planned drivers. Additional drivers may be introduced over time without changing the Lead module — only a new driver registration is required.

DriverStatusNotes
Manual Lead DriverPlannedSPA / API create path expressed as a driver (or thin adapter)
CSV Import DriverPlannedEvolve today’s file import onto the shared pipeline
Public API DriverPlannedExternal create API → normalize → pipeline
Website Form DriverPlannedGeneric hosted / embedded web forms
Meta Lead Ads DriverShippedSee Meta Lead Ads
WhatsApp DriverPlannedInbound lead capture from WhatsApp — see also WhatsApp Cloud Integration (messaging)
Google Ads DriverPlannedLead form extensions / offline import
Google Forms DriverPlannedForm responses → leads
LinkedIn Lead Gen DriverPlannedLinkedIn Lead Gen Forms
TikTok Lead DriverPlannedTikTok lead generation ads
Gravity Forms DriverPlannedWordPress Gravity Forms
Contact Form 7 DriverPlannedWordPress CF7
Elementor Forms DriverPlannedElementor form submissions
Typeform DriverPlannedTypeform webhooks
Jotform DriverPlannedJotform webhooks
HubSpot Import DriverPlannedCRM import / sync adapter
Salesforce Import DriverPlannedCRM import / sync adapter
Zoho Import DriverPlannedCRM import / sync adapter
Pipedrive Import DriverPlannedCRM import / sync adapter
Custom Webhook DriverShippedSee Custom Lead Webhook

Shipped drivers are live in application code. Remaining catalog entries are roadmap placeholders, not delivery commitments.


NormalizedLeadData DTO

Logical DTO produced by every driver. This is not a finalized class definition — field names and nesting may evolve during implementation. The contract is: drivers emit one common shape; the Lead module consumes only that shape.

Identity

FieldPurpose
nameFull name
emailEmail address
phonePhone number
companyCompany name

Source

FieldPurpose
sourceHuman / canonical source label (e.g. Meta Lead Ads)
source_referenceDriver / channel identifier
external_idIdempotency key from the external system

Marketing attribution

FieldPurpose
campaign_idCampaign identifier
campaign_nameCampaign display name
adset_idAd set identifier
adset_nameAd set display name
ad_idAd identifier
ad_nameAd display name
form_idForm identifier
form_nameForm display name

Tracking

FieldPurpose
utm_sourceUTM source
utm_mediumUTM medium
utm_campaignUTM campaign
utm_contentUTM content
utm_termUTM term

Metadata

FieldPurpose
custom_fieldsSource-specific questions / extras as structured data
tagsSuggested tags (applied by Lead rules, not by the driver writing tag rows)
received_atWhen the platform received the submission
payloadSafe reference or redacted raw payload for audit / dead-letter diagnosis

Illustrative shape:

json
{
  "name": "Ada Lovelace",
  "email": "ada@example.com",
  "phone": "+1-555-0100",
  "company": "Analytical Engines",
  "source": "Meta Lead Ads",
  "source_reference": "meta_lead_ads",
  "external_id": "1234567890",
  "campaign_id": "...",
  "campaign_name": "...",
  "adset_id": "...",
  "adset_name": "...",
  "ad_id": "...",
  "ad_name": "...",
  "form_id": "...",
  "form_name": "...",
  "utm_source": null,
  "utm_medium": null,
  "utm_campaign": null,
  "utm_content": null,
  "utm_term": null,
  "custom_fields": {
    "budget": "10k-50k"
  },
  "tags": ["meta", "inbound"],
  "received_at": "2026-07-20T10:00:00Z",
  "payload": { "redacted": true }
}

Driver responsibilities

Drivers are responsible for:

  • Receiving payloads (webhook, poll, upload, API)
  • Authentication
  • Signature verification (when the source provides it)
  • Token refresh / reconnect signaling
  • Payload validation
  • Mapping external fields
  • Producing NormalizedLeadData

Drivers must not perform:

  • Duplicate detection
  • Assignment
  • Notifications
  • Automation
  • Database writes
  • Activity logging
  • Stage calculation
  • Business rules

Core Lead responsibilities

The Lead module owns:

  • Duplicate detection (LeadDuplicateService)
  • Lead creation (LeadService only)
  • Assignment
  • Activities
  • Notes
  • Follow-ups
  • Notifications
  • Automation hooks
  • Timeline
  • Stage resolution
  • Conversion
  • Validation of business rules

Drivers stop at NormalizedLeadData. Everything after that is Lead / platform territory.


Error handling

Standard failure path for normalization (and equivalent driver-side failures after auth succeeds):

text
Failures during normalization

Dead-letter queue

Retry

Alert

Manual import if necessary
RuleDetail
Idempotent driversSafe to reprocess the same external event
Duplicate webhook deliveriesMust not create duplicate leads (external_id + pipeline duplicate gate)
Auth / signature failureReject at the edge; do not enter the Lead pipeline
Poison messagesAfter retries, alert operators; allow manual recovery via existing import tools when needed

Extensibility principles

Adding a new lead source should require:

  • Creating a new driver

Only.

PrincipleMeaning
Open/ClosedOpen to new sources via drivers; closed to Lead-module edits for each source
No duplicationExisting duplicate, assignment, notification, and activity logic is never reimplemented in a driver
Stable Lead coreNew sources do not fork Lead validation, stages, or conversion rules
Registry growthA driver catalog / registry grows; LeadService remains the single writer

This mirrors the payment-gateway and email-driver patterns already used elsewhere on the platform: adapters at the edge, shared engine in the center — without redesigning the frozen foundation.


Relationship with Meta Lead Ads

Meta Lead Ads Integration is the first concrete consumer of this architecture.

  • MetaLeadAdsDriver will be the first production implementation of the Lead Source Driver Architecture.
  • Meta-specific OAuth, Page subscription, Graph fetch, and field mapping live only inside that driver.
  • After normalize(), Meta leads use the same pipeline as every other source: NormalizedLeadDataLeadDuplicateServiceLeadService → activities / assignment / notifications / automations / timeline.

Do not implement Meta Lead Ads by embedding Graph parsing inside LeadService or Lead controllers.


Official documentation for the SaleOS SaaS Platform.