Skip to content

CRM Reports Guide

Overview

CRM Reports provide the analytical layer over your customer relationship data. Four purpose-built report endpoints aggregate and structure data across leads, customers, activities, and open opportunities, giving revenue and operations teams a clear view of pipeline health, team performance, and customer acquisition patterns without needing to build queries manually.

Reports are read-only analytical views. They do not modify any records; they summarise existing CRM data within a specified time window. Each report accepts a period shorthand (7, 30, or 90 days from today) or explicit date_from/date_to parameters for custom ranges. All reports are scoped to the current tenant and respect the authenticated user's access level.

Report Types

ReportEndpointPrimary Question
Lead ConversionGET /reports/lead-conversionHow many leads progressed through each funnel stage, and at what rate?
Customer AcquisitionGET /reports/customer-acquisitionHow many new customers were acquired, through which channels, and at what value?
Activity SummaryGET /reports/activity-summaryAre activities being completed on time, and how is workload distributed across the team?
Sales PipelineGET /reports/sales-pipelineWhat is the current pipeline value, how is it distributed by stage, and what does the forecast look like?

API Endpoints

All report endpoints are under the base path /api/v1/crm/reports.

Authentication: Required (Bearer token) for all endpoints.


1. Lead Conversion Report

Analyses lead volume and conversion rates across the qualification funnel for a given period.

Endpoint: GET /api/v1/crm/reports/lead-conversion

Query Parameters:

ParameterTypeDefaultDescription
periodinteger30Preset window in days: 7, 30, or 90. Ignored if date_from/date_to are provided
date_fromdate (YYYY-MM-DD)-Start of custom date range
date_todate (YYYY-MM-DD)-End of custom date range

Example Requests:

bash
# Last 30 days (default)
GET /api/v1/crm/reports/lead-conversion

# Last 90 days
GET /api/v1/crm/reports/lead-conversion?period=90

# Custom range
GET /api/v1/crm/reports/lead-conversion?date_from=2025-10-01&date_to=2025-10-31

Response (200 OK):

json
{
  "success": true,
  "message": "Lead conversion report generated successfully",
  "data": {
    "period": {
      "from": "2025-10-01",
      "to": "2025-10-31"
    },
    "funnel": {
      "new": 120,
      "contacted": 87,
      "qualified": 45,
      "converted": 18
    },
    "conversion_rates": {
      "new_to_contacted": 0.725,
      "contacted_to_qualified": 0.517,
      "qualified_to_converted": 0.400,
      "overall": 0.150
    },
    "trends": [
      { "date": "2025-10-01", "leads": 4, "converted": 1 },
      { "date": "2025-10-02", "leads": 3, "converted": 0 },
      { "date": "2025-10-03", "leads": 5, "converted": 2 }
    ]
  },
  "meta": {}
}

Response Fields:

FieldDescription
funnelCounts of leads that reached each status within the period
conversion_rates.new_to_contactedFraction of new leads that reached "contacted"
conversion_rates.contacted_to_qualifiedFraction of contacted leads that reached "qualified"
conversion_rates.qualified_to_convertedFraction of qualified leads that converted
conversion_rates.overallEnd-to-end conversion rate from new to converted
trendsDaily breakdown of leads created and converted for the period

Funnel Stage Counts

Funnel counts represent leads that reached a given status during the period, not cumulative totals. A lead that entered "contacted" on day 1 and "qualified" on day 15 contributes to both contacted and qualified counts.


2. Customer Acquisition Report

Measures new customer acquisition volume, channel attribution, and customer lifetime value indicators for a given period.

Endpoint: GET /api/v1/crm/reports/customer-acquisition

Query Parameters:

ParameterTypeDefaultDescription
periodinteger30Preset window in days: 7, 30, or 90
date_fromdate (YYYY-MM-DD)-Start of custom date range
date_todate (YYYY-MM-DD)-End of custom date range

Example Requests:

bash
# Last 30 days
GET /api/v1/crm/reports/customer-acquisition

# Last 7 days
GET /api/v1/crm/reports/customer-acquisition?period=7

# Specific quarter
GET /api/v1/crm/reports/customer-acquisition?date_from=2025-10-01&date_to=2025-12-31

Response (200 OK):

json
{
  "success": true,
  "message": "Customer acquisition report generated successfully",
  "data": {
    "period": {
      "from": "2025-10-01",
      "to": "2025-10-31"
    },
    "total_new_customers": 18,
    "by_channel": {
      "website": 7,
      "referral": 4,
      "cold_outreach": 3,
      "trade_show": 2,
      "paid_search": 2
    },
    "high_value_customers": [
      {
        "id": "01hwcust00000000000000001",
        "name": "TechCorp Inc",
        "acquired_at": "2025-10-12T10:00:00Z",
        "estimated_lifetime_value": 150000.00
      },
      {
        "id": "01hwcust00000000000000002",
        "name": "Global Retail Group",
        "acquired_at": "2025-10-18T14:30:00Z",
        "estimated_lifetime_value": 95000.00
      }
    ],
    "average_clv": 42300.00
  },
  "meta": {}
}

Response Fields:

FieldDescription
total_new_customersCustomers created (converted from leads) within the period
by_channelAcquisition count broken down by the originating lead source
high_value_customersTop customers acquired in the period, ordered by estimated lifetime value
average_clvMean estimated lifetime value across all customers acquired in the period

3. Activity Summary Report

Summarises activity completion rates, type distribution, and per-user workload for a given period.

Endpoint: GET /api/v1/crm/reports/activity-summary

Query Parameters:

ParameterTypeDefaultDescription
periodinteger30Preset window in days: 7, 30, or 90

Example Requests:

bash
# Last 30 days
GET /api/v1/crm/reports/activity-summary

# Last week
GET /api/v1/crm/reports/activity-summary?period=7

Response (200 OK):

json
{
  "success": true,
  "message": "Activity summary report generated successfully",
  "data": {
    "period_days": 30,
    "total": 342,
    "completed": 278,
    "pending": 41,
    "overdue": 23,
    "completion_rate": 0.813,
    "billable_hours": 186.5,
    "by_type": {
      "call": 124,
      "email": 98,
      "meeting": 67,
      "task": 53
    },
    "by_user": [
      {
        "user_id": "01hwuser0000000000000001",
        "user_name": "Jane Davis",
        "total": 89,
        "completed": 75,
        "overdue": 4,
        "completion_rate": 0.843
      },
      {
        "user_id": "01hwuser0000000000000002",
        "user_name": "John Smith",
        "total": 76,
        "completed": 61,
        "overdue": 7,
        "completion_rate": 0.803
      }
    ]
  },
  "meta": {}
}

Response Fields:

FieldDescription
totalAll activities scheduled within or carried into the period
completedActivities marked as complete
pendingActivities not yet due
overdueActivities past their due date and not completed
completion_ratecompleted / total ratio
billable_hoursSum of duration for billable activities in the period
by_typeActivity counts by type (call, email, meeting, task)
by_userPer-user breakdown with individual completion rates and overdue counts

Overdue Activities

A high overdue count relative to total (above ~10%) is a signal that activity SLAs are not being met. Use the by_user breakdown to identify which team members need workload redistribution or coaching.


4. Sales Pipeline Report

Analyses the current open opportunity pipeline by stage, assigned user, and deal age, and projects revenue under three forecast scenarios.

Endpoint: GET /api/v1/crm/reports/sales-pipeline

Query Parameters:

ParameterTypeDefaultDescription
periodinteger30Preset window in days: 7, 30, or 90. Determines the "created within period" filter for new pipeline entries

Example Requests:

bash
# Current pipeline snapshot (default 30-day window for new entries)
GET /api/v1/crm/reports/sales-pipeline

# Opportunities created in the last quarter
GET /api/v1/crm/reports/sales-pipeline?period=90

Response (200 OK):

json
{
  "success": true,
  "message": "Sales pipeline report generated successfully",
  "data": {
    "period_days": 30,
    "total_opportunities": 64,
    "pipeline_value": 2840000.00,
    "weighted_value": 1138500.00,
    "average_deal_size": 44375.00,
    "by_stage": {
      "prospect": {
        "count": 18,
        "value": 540000.00,
        "weighted_value": 81000.00
      },
      "proposal": {
        "count": 22,
        "value": 980000.00,
        "weighted_value": 392000.00
      },
      "negotiation": {
        "count": 15,
        "value": 875000.00,
        "weighted_value": 525000.00
      },
      "closing": {
        "count": 9,
        "value": 445000.00,
        "weighted_value": 400500.00
      }
    },
    "by_user": [
      {
        "user_id": "01hwuser0000000000000001",
        "user_name": "Jane Davis",
        "opportunities": 21,
        "pipeline_value": 1050000.00,
        "weighted_value": 412500.00
      },
      {
        "user_id": "01hwuser0000000000000002",
        "user_name": "John Smith",
        "opportunities": 18,
        "pipeline_value": 890000.00,
        "weighted_value": 356000.00
      }
    ],
    "aging": {
      "under_30_days": 29,
      "30_to_60_days": 18,
      "60_to_90_days": 11,
      "over_90_days": 6
    },
    "forecast": {
      "best_case": 2840000.00,
      "most_likely": 1138500.00,
      "worst_case": 712000.00
    }
  },
  "meta": {}
}

Response Fields:

FieldDescription
total_opportunitiesCount of open opportunities (excludes won and lost)
pipeline_valueSum of opportunity values at full deal size
weighted_valueSum of opportunity_value * probability across all open opportunities
average_deal_sizepipeline_value / total_opportunities
by_stagePipeline breakdown per stage with raw and probability-weighted values
by_userPer-rep pipeline value and weighted value
agingOpportunity counts grouped by days since creation
forecast.best_caseFull pipeline value - assumes all opportunities close
forecast.most_likelyWeighted pipeline value - uses probability-adjusted amounts
forecast.worst_caseConservative estimate based on late-stage, high-probability deals only

Aging Buckets:

BucketDays Since Creation
under_30_days0–29 days
30_to_60_days30–60 days
60_to_90_days61–90 days
over_90_days91+ days

Aging Pipeline Risk

Opportunities in the over_90_days bucket have a significantly higher probability of going stale or being lost. Any opportunity in this bucket without recent activity should be reviewed by the assigned rep immediately.

Business Scenarios

Scenario 1: Monthly Executive Revenue Review

Context: A revenue leader needs to compile a monthly performance report covering pipeline health, acquisition, and team activity before a board presentation.

Workflow:

  1. Pull lead conversion for the month to show funnel efficiency
  2. Pull customer acquisition for the month to show net-new revenue
  3. Pull sales pipeline for the current state of open deals
  4. Compile weighted pipeline value as the headline forecast number
bash
# 1. Lead funnel performance for October
GET /api/v1/crm/reports/lead-conversion?date_from=2025-10-01&date_to=2025-10-31

# 2. New customer acquisition for October
GET /api/v1/crm/reports/customer-acquisition?date_from=2025-10-01&date_to=2025-10-31

# 3. Current pipeline snapshot
GET /api/v1/crm/reports/sales-pipeline?period=90

# Key metrics to surface:
# - conversion_rates.overall from lead-conversion
# - total_new_customers and average_clv from customer-acquisition
# - weighted_value and forecast.most_likely from sales-pipeline

The three reports together give a full-funnel picture: leads entering at the top, customers exiting at the bottom, and revenue forecast from open deals in the middle.


Scenario 2: Sales Team Performance Review

Context: A sales manager wants to identify which reps are carrying their pipeline effectively and which need coaching before end of quarter.

Workflow:

  1. Pull the activity summary to check completion rates by user
  2. Pull the pipeline report and inspect the by_user breakdown
  3. Cross-reference reps with high overdue activity rates against pipeline performance
  4. Schedule 1:1s with reps showing both low pipeline value and high overdue count
bash
# 1. Activity completion by rep for last 30 days
GET /api/v1/crm/reports/activity-summary?period=30

# 2. Pipeline by rep
GET /api/v1/crm/reports/sales-pipeline?period=90

# Warning signals:
# - activity by_user.completion_rate < 0.75
# - pipeline by_user.weighted_value significantly below team average
# - aging.over_90_days count > 3 for a single rep

Scenario 3: Channel Effectiveness and Budget Allocation

Context: A marketing team wants to understand which acquisition channels are producing the highest-value customers in order to reallocate budget for the next quarter.

Workflow:

  1. Pull customer acquisition for the last quarter
  2. Compare by_channel counts against channel spend from your marketing tools
  3. Cross-reference with lead conversion to see which source produces the highest conversion rate
  4. Bring both data sets to the budget planning meeting
bash
# Customer acquisition breakdown for Q4 2025
GET /api/v1/crm/reports/customer-acquisition?date_from=2025-10-01&date_to=2025-12-31

# Lead conversion for the same period to see source-level funnel efficiency
GET /api/v1/crm/reports/lead-conversion?date_from=2025-10-01&date_to=2025-12-31

Channels with high by_channel count and high average_clv are the priority candidates for increased investment.

Best Practices

1. Use period Shorthand for Operational Dashboards

For live dashboards that refresh automatically (e.g., a sales operations screen that updates hourly), use the period parameter rather than hardcoded dates. ?period=30 always returns the trailing 30 days from today, so dashboards stay current without date calculation on the client side.

2. Use date_from/date_to for Historical Comparisons

When comparing performance across defined periods (e.g., Q3 vs Q4, or year-over-year), always use explicit date_from and date_to parameters. This ensures the comparison windows are fixed and repeatable regardless of when the report is run.

3. Treat forecast.most_likely as Your Primary Forecast Number

The pipeline report provides three forecast scenarios. For internal planning, forecast.most_likely (probability-weighted pipeline value) is the most reliable single number. Use forecast.best_case only for optimistic ceiling modelling and forecast.worst_case as a floor for cash flow planning.

4. Monitor aging.over_90_days Weekly

Deals that have been in the pipeline for more than 90 days without progressing are a leading indicator of pipeline bloat and inflated forecasts. Add a weekly check of this bucket to your sales meeting cadence, and apply a manual probability override or close any deal that cannot be justified at its current stage.

Integration Points

With Lead Management

The lead conversion report draws its funnel data from the same lead records managed through the leads API. Improving lead qualification processes (better scoring, faster follow-up, clearer BANT criteria) will be directly reflected in improvements to conversion_rates.overall. Refer to the Lead Management guide for lead lifecycle management.

With Opportunity Pipeline

The sales pipeline report is the analytical counterpart to the opportunity management workflow. Opportunities created and progressed through the pipeline API are the source of record for all pipeline report data. Refer to the Opportunity Pipeline guide for how to manage individual opportunities.

With Activity Management

The activity summary report aggregates data from all CRM activities. Maintaining a clean and up-to-date activity log (completing or rescheduling overdue items promptly) is what makes the activity report actionable. Refer to the Activity Management guide for managing activities.

When a report surfaces a data point worth investigating further (e.g., a single rep with unusually low pipeline), use the CRM Search endpoints to drill into that rep's specific leads, contacts, and opportunities directly.

Troubleshooting

Report Returns Empty or Zero Counts

Symptom: A report returns 200 OK but all numeric fields are 0 or arrays are empty.

Possible Causes:

  • The selected period or date range predates any data in the system
  • No CRM records have been created yet
  • The authenticated user lacks permissions to view CRM data for the tenant

Solution:

  1. Confirm CRM records exist by running a basic list query:
    bash
    GET /api/v1/crm/leads?per_page=5
  2. If records exist, try widening the period to 90 days or using explicit date_from/date_to parameters that span a known active range.
  3. Verify the user's Bouncer role includes the crm.reports.view permission.

forecast.most_likely Appears Inflated

Symptom: The weighted pipeline value (forecast.most_likely) seems unrealistically high compared to actual close rates.

Cause: Opportunity probability values have not been kept current as deals age. Older opportunities in early stages retain their initial probability (e.g., 25%) even though their realistic close probability has declined.

Solution:

  1. Review opportunities in the aging.over_90_days bucket:
    bash
    GET /api/v1/crm/reports/sales-pipeline?period=90
    # Check aging.over_90_days count
  2. For each stale opportunity, update the probability to reflect current deal reality via the opportunities API, or close it as lost.
  3. Establish a process where reps review and update opportunity probabilities at least once per month.

Documentation for SynthesQ CRM/ERP Platform