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:
- "Which deals are expected to close this week?"
- "Are any target close dates overdue and getting stale?"
- "How much revenue is projected to close by month-end?"
Quick Direct URL Test Options
While logged in, you can also trigger instant exports directly via your browser address bar:
Export All Active Deals:
[https://leadspilot.com/public/api/export_csv.php?type=deals](https://leadspilot.com/public/api/export_csv.php?type=deals)
Export This Month's Deals:
[https://leadspilot.com/public/api/export_csv.php?type=deals&range=this_month](https://leadspilot.com/public/api/export_csv.php?type=deals&range=this_month)
Export All Activity History:
[https://leadspilot.com/public/api/export_csv.php?type=activities](https://leadspilot.com/public/api/export_csv.php?type=activities)
Export Contacts Directory:
[https://leadspilot.com/public/api/export_csv.php?type=contacts](https://leadspilot.com/public/api/export_csv.php?type=contacts)
Core Views You Can Build
1. Executive Analytics Dashboard (public/stats.php) A high-level view (best restricted to admin or sales managers) showing macro pipeline metrics:
Top Summary Cards:
Won Revenue (This Month): SUM(value) where stage = 'won' and updated this month.
Open Pipeline Value: Total $value sitting in lead, contacted, proposal, negotiation.
Pipeline Win Rate: $\frac{\text{Won Deals}}{\text{Won Deals} + \text{Lost Deals}} \times 100$.
Quotes Sent: Count of activities where type = 'email' and subject = 'Quote Email Initiated'.
Conversion Funnel Breakdown:Count and total value of deals currently sitting in each stage.
Sales Rep Leaderboard:Grouping activities and won deals by user_id to see who is driving the most outreach and closing the most value.
2. Calendar & Deal Progress View (public/calendar.php)
A time-focused view that gives sales reps a clear breakdown of upcoming close dates and daily activity consistency:Monthly Expected Closings:Group open deals by their expected_close_date column in a lightweight monthly calendar grid or weekly agenda list.Allows reps to see at a glance if $\$20,\!000$ worth of deals are supposed to close this Friday so they can follow up in advance.Daily Activity Progress Tracker:A streak or daily count widget showing how many activities (emails sent, stage updates, notes added) were logged today vs. daily targets.
How calendar.php Filters and Displays Dealscalendar is intentionally scoped so it doesn't clutter the view with unrelated dates. It applies three distinct filters: Month & Year Scope: By default, calendar.php only fetches deals scheduled to close in the currently selected month (e.g., October 2026). If you save a deal with a target close date in November or December, it will not appear on the current screen unless you click the Next ▶ button to navigate to that month. expected_close_date IS NOT NULL: Any deal with an empty/unpopulated target date is completely excluded from the calendar. Overdue vs. Active Deals:Past Active Deals: If a target date was in the past (before today) and the stage is still active (lead, contacted, proposal, negotiation), it appears in the top ⚠️ Overdue Closing Dates card. Past Closed Deals: If a past deal is marked won or lost, it is hidden from the overdue list.
Why is a deal not appearing on the Calendar?
Check the following conditions if a deal is missing:
Unassigned Close Date: Ensure a date is explicitly set in the Target Expected Close Date field.
PHP
Selected Month Filter: Verify if the target close date falls in a different month. Use ◀ Prev / Next ▶ to check adjacent months.
PHP
Archived Status: Archived deals (is_archived = 1) are automatically excluded.
PHP+ 1
Why did a target date disappear after updating a deal?
Ensure that $rawDeals in public/index.php includes d.expected_close_date in its SELECT list. If omitted from the main pipeline payload, saving an edit without re-selecting the date input will clear the date in the database.
PHP+ 1
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
<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()).
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())