System Overview

Welcome to the official documentation for Leads Pilot.

Leads Pilot is a lightweight, multi-tenant B2B CRM and pipeline management software[cite: 1]. It is intentionally designed with zero external framework dependencies to ensure fast performance and secure data isolation[cite: 1].

Getting Started

To begin using Leads Pilot, you will log into your dedicated agency workspace. Every workspace operates in strict isolation, ensuring that all companies, contacts, and pipeline deals are securely scoped to your unique agency identity[cite: 1].

Understanding CRM Entities

Leads Pilot separates data into three distinct architectural layers to prevent duplication and improve relationship tracking.

Companies

Companies serve as the primary organizational accounts. A single company can house multiple contacts and active leads.

Contacts

Contacts are the human individuals associated with a company. You can add activities, notes, and log interactions against individual contacts[cite: 1].

Leads (Pipeline Deals)

Leads represent active sales opportunities. When adding a new lead to the pipeline, you will associate it with an existing Company and Contact.

Notes on entry mechanics
    Separating entity management into Companies, Contacts, and Deals/Leads is the standard architecture across CRM platforms (such as Salesforce or HubSpot) because each entity represents a distinct conceptual layer in B2B transactions:

    Companies (Accounts): Represent the organizational entity (e.g., Acme Corp).

    Contacts: Represent individual human beings who work at that company (e.g., Jane Doe, VP of Marketing).

    Leads / Deals: Represent a active, temporal sales opportunity or pipeline card (e.g., $15,000 Web Design Project).

While having separate entry mechanisms for Companies and Contacts alongside "Add New Lead" might initially seem redundant, using "Associated Company" and "Associated Contact" fields inside the Add New Lead flow is both practical and essential for agency workflows.
Why the Separate Entry Points Exist

    Database Normalization (Many-to-One / Many-to-Many Relationships):
    A single company may have multiple contacts (e.g., CEO, Procurement, IT Lead). Similarly, a single company or contact may have multiple active or past leads over time (e.g., a retainer deal in 2025 and an upsell deal in 2026). If leads, contacts, and companies were all bundled into a single entry form without separation, agencies would suffer from duplicated data, inconsistent reporting, and lost activity history.

    Non-Sales Touchpoints:
    Agencies often add contacts or companies before an actual sales opportunity exists (e.g., importing event attendee lists, partner directories, or cold outreach lists).

Will Agencies Understand Why It's Structured This Way?

Yes—provided the UX/UI sets clear expectations.

Agencies accustomed to modern sales software expect relational mapping (linking a deal to a contact/company). However, friction or confusion can arise depending on how the "Add New Lead" form handles those associations:
Potential UX Pitfalls & Misunderstandings

    "Do I have to create the Company/Contact first?"

        Confusion: If a user opens "Add New Lead" and the "Associated Company" dropdown requires the company to already exist in the database, users get frustrated by having to leave their tab, create a company/contact, and come back.

        Solution (Inline Creation): The "Add New Lead" entry form should allow inline creation—letting users type a new company or contact name directly into the search/select field and click "Create new Company/Contact" on the fly without breaking their workflow.

    Lead vs. Contact Ambiguity:

        Confusion: Smaller agencies or teams transitioning from spreadsheets often confuse a "Lead" (the sales deal) with a "Contact" (the person). They might ask: "Why am I adding Jane Doe as a Lead AND as a Contact?"

        Solution: Labeling and context. Clarifying that a Lead is the Opportunity/Deal (with a dollar value, stage, and close date) while the Contact is the Person attached to it resolves this gap.

    Multi-Contact / Multi-Deal Realities:

        Practicality: By keeping companies and contacts separated, an agency rep can look at a single Company profile and see all associated Contacts, past notes, and active pipeline deals in one centralized view.

Best Practices for Lead Entry Design

To ensure agency users find the entry mechanisms intuitive rather than disjointed:

    Primary Quick Action ("Add New Lead"): Make the "Add Lead" modal the primary action button on pipeline views. Allow users to select existing Contacts/Companies via an auto-complete lookup or create new ones inline within the same form.

    Auto-Population: If a user clicks "Add New Lead" directly from a specific Company or Contact page, automatically pre-fill the "Associated Company" or "Associated Contact" fields.

    Contextual Helpers: Subtle microcopy under association fields (e.g., "Link this deal to a primary point of contact and company") reinforces the distinction between the sales opportunity and the people involved.

Agency Workspaces (Multi-Tenancy)

Your data is strictly partitioned. Leads Pilot utilizes workspace isolation per agency via an agency_id[cite: 1]. Every action you perform—from creating a lead to logging a note—is exclusively tied to your workspace[cite: 1].

Roles & Permissions

Access control is divided into specific user tiers to protect sensitive pipeline configurations[cite: 1].

Admin

Admins have full workspace management capabilities[cite: 1]. This includes access to the dedicated /archive.php portal where admins can review archived pipeline entries, restore them, or perform permanent entry purging[cite: 1].

Sales Rep / User

Sales Reps have operational access. They can manage the pipeline, add or move deals, and create contact activities or notes, but cannot permanently delete pipeline entries[cite: 1].

Moving Deals

Sales reps and users can actively manage the pipeline by advancing leads through various stages[cite: 1].

Every time a sales rep or admin uses the quick dropdown in the pipeline table to move a deal to "Proposal Sent" or "Negotiation", a new activity record is written to MySQL with the current user's id, agency_id, timestamp, and description. Whenever a deal is updated from the Edit Modal, a record with the updated stage and contact ID is logged automatically.

Archiving & Restoring

To keep the active pipeline clean, outdated or lost deals should be archived rather than immediately deleted. Only Admin users can restore archived entries or permanently purge them from the database[cite: 1].

Executive Analytics Dashboard

While the pipeline answers "Where are deals sitting?", the Calendar view answers:

Importing API or csv

Zero-Code Web Form Pointing: An agency admin can take their website's existing HTML contact form and simply change the action attribute:

Payload Flexibility & Smart Mapping: The endpoint inspects common incoming form field keys and maps them automatically:
name / first_name / last_name $\rightarrow$ contacts
email / phone $\rightarrow$ contacts
company / business_name $\rightarrow$ companies
message / comments / notes $\rightarrow$ deals.notes
value / budget $\rightarrow$ deals.value

CSV Data Importer (Onboarding Migration Tool) Concept & Admin Viability

  • Integration Examples for Agency Users - Example A: Standard HTML Contact Form (Zero Code)
  • An agency can point any existing website form directly to their endpoint: HTML
  • 
    <form action="https://yourdomain.com/api/v1/lead_capture.php?api_key=YOUR_API_KEY" method="POST">
      <input type="text" name="name" placeholder="Your Name" required>
      <input type="email" name="email" placeholder="Your Email" required>
      <input type="tel" name="phone" placeholder="Phone Number">
      <input type="text" name="company" placeholder="Company Name">
      <textarea name="message" placeholder="Project details...">
      <button type="submit">Submit Inquiry</button>
    

    curl Test Command

    
    curl -X POST https://yourdomain.com/api/v1/lead_capture.php \
      -H "X-LP-API-KEY: YOUR_WORKSPACE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "John Doe",
        "email": "john@example.com",
        "phone": "123-456-7890",
        "company": "Apex Dynamics",
        "notes": "Testing inbound webhook lead capture."
      }'
    

    JavaScript fetch() / AJAX (WordPress, Webflow, React)

    async function sendWebLead(formData) { const response = await fetch('https://yourdomain.com/api/v1/lead_capture.php', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-LP-API-KEY': 'YOUR_WORKSPACE_API_KEY' }, body: JSON.stringify({ name: "Jane Smith", email: "jane@acmecorp.com", phone: "555-0199", company: "Acme Corp", value: 2500.00, notes: "Interested in the 5-page site redesign package." }) }); const result = await response.json(); console.log(result); }
    
    - Admin UI WorkflowFile Upload: Admin selects a .csv file.
    - Column Mapping Step: A clean Vanilla JS table parses the header row and lets the admin map CSV headers to system fields:
    
    - CSV Column 1 ("Company Name") $\rightarrow$ Map to Company Name
    - CSV Column 2 ("Contact Email") $\rightarrow$ Map to Contact Email
    - CSV Column 3 ("Deal Value") $\rightarrow$ Map to Deal Estimated Value
    - CSV Column 4 ("Pipeline Stage") $\rightarrow$ Map to Deal Stage (with fallback to lead)
            

    Both tools leverage a single backend service method inside PHP (e.g., IngestionEngine::processLead()).

    // Standardized Ingestion Pipeline (Used by Webhook & CSV Importer)
    1. Resolve or Create Company:
       IF company_name is provided:
         Search: SELECT id FROM companies WHERE name = :name AND agency_id = :agency_id
         IF exists: $companyId = existing.id
         ELSE: Insert new company -> $companyId = lastInsertId
    
    2. Resolve or Create Contact:
       IF contact_email is provided:
         Search: SELECT id FROM contacts WHERE email = :email AND agency_id = :agency_id
         IF exists: $contactId = existing.id
         ELSE: Insert new contact (linked to $companyId) -> $contactId = lastInsertId
    
    3. Create Pipeline Deal:
       Insert into deals (agency_id, title, value, stage, notes, contact_id, company_id, created_at)
       Values (:agency_id, :title, :value, :stage, :notes, $contactId, $companyId, NOW())
    
    4. Log Activity Entry:
       Insert into activities (agency_id, user_id, deal_id, contact_id, type, subject, content, created_at)
       Values (:agency_id, :system_user_or_admin, $dealId, $contactId, 'note', 'Inbound Lead Created', :source_notes, NOW())
        
    run a quick test submission using curl