Opportunity Pipeline Management Guide
Overview
Opportunities represent potential revenue from qualified leads and existing customers. The opportunity pipeline provides a structured framework for tracking deals through predictable stages from initial contact to closed-won. This guide covers the complete opportunity lifecycle, stage management, forecasting, and best practices for maximizing win rates.
Opportunity Lifecycle
Pipeline Stages
Opportunities progress through defined stages representing the sales process:
| Stage | Probability | Description | Typical Duration | Key Activities |
|---|---|---|---|---|
| Prospecting | 10% | Initial contact, gathering basic information | 1-2 weeks | Discovery calls, needs assessment |
| Qualification | 25% | BANT qualification, fit assessment | 1-2 weeks | Budget confirmation, stakeholder identification |
| Needs Analysis | 40% | Deep discovery, solution mapping | 2-3 weeks | Requirements gathering, technical discovery |
| Proposal | 60% | Formal proposal presented | 1-2 weeks | Proposal creation, presentation, feedback |
| Negotiation | 75% | Terms negotiation, contracting | 1-3 weeks | Pricing negotiation, legal review, MSA |
| Verbal Commitment | 90% | Verbal agreement secured | 3-7 days | Final approvals, paperwork preparation |
| Won | 100% | Deal closed successfully | N/A | Contract signed, onboarding initiated |
| Lost | 0% | Deal lost to competitor or no decision | N/A | Loss analysis, documentation |
| On Hold | 0% | Deal temporarily paused | Variable | Waiting for budget, timing, decision |
Stage Transitions
Valid stage progressions:
Prospecting → Qualification → Needs Analysis → Proposal → Negotiation → Verbal Commitment → Won
Any Active Stage → Lost (deal can be lost at any time)
Any Active Stage → On Hold (deal can be paused)
On Hold → Any Previous Active Stage (deal can be resumed)Invalid Transitions
The system enforces valid stage transitions. You cannot skip stages (e.g., Prospecting → Proposal) or move backward in the pipeline without valid reason. Won and Lost are terminal states.
Creating Opportunities
Create New Opportunity
Endpoint: POST /api/v1/crm/opportunities
Authentication: Required (Bearer token)
Request Body:
{
"name": "Acme Corp - Enterprise Platform Implementation",
"description": "Full platform deployment for 500 users across 5 departments. Includes professional services for custom integration with legacy systems.",
"customer_id": 568,
"lead_id": 1234,
"stage": "qualification",
"value": 150000.00,
"expected_revenue": 150000.00,
"currency": "USD",
"probability": 25,
"expected_close_date": "2026-03-31",
"source": "lead_conversion",
"priority": "high",
"assigned_user_id": 7,
"campaign_id": 456,
"territory": "North America - Enterprise",
"competitor": "Competitor X",
"decision_maker": "Jane Smith, CTO",
"budget_confirmed": true,
"authority_confirmed": true,
"need_confirmed": true,
"timeline_confirmed": false,
"next_step": "Schedule technical discovery call with IT team",
"discovery_notes": "Initial call with CTO. Clear need for integration platform. Budget approved. Timeline flexible but prefer Q1 implementation.",
"tags": ["enterprise", "integration", "professional-services"],
"custom_fields": {
"implementation_complexity": "high",
"user_count": 500,
"departments": 5
}
}Required Fields:
name- Opportunity namecustomer_id- Associated customervalue- Deal valueexpected_close_date- Target close datestage- Initial stage (defaults toprospecting)
Optional Fields:
lead_id- Originating leadprobability- Win probability (auto-calculated from stage if not provided)source- Opportunity sourcepriority- Priority level (low, medium, high)assigned_user_id- Opportunity owner- BANT fields - Budget, Authority, Need, Timeline confirmation flags
next_step- Next action required- Various notes fields for tracking progress
Response (201 Created):
{
"message": "Opportunity created successfully",
"data": {
"id": 890,
"name": "Acme Corp - Enterprise Platform Implementation",
"customer_id": 568,
"lead_id": 1234,
"stage": "qualification",
"value": 150000.00,
"expected_revenue": 150000.00,
"weighted_value": 37500.00,
"currency": "USD",
"probability": 25,
"expected_close_date": "2026-03-31",
"source": "lead_conversion",
"priority": "high",
"assigned_user": {
"id": 7,
"name": "Jane Manager",
"email": "jane@yourcompany.com"
},
"budget_confirmed": true,
"authority_confirmed": true,
"need_confirmed": true,
"timeline_confirmed": false,
"bant_score": 3,
"next_step": "Schedule technical discovery call with IT team",
"created_at": "2025-12-17T20:00:00Z",
"updated_at": "2025-12-17T20:00:00Z"
}
}Listing and Filtering Opportunities
Get All Opportunities
Endpoint: GET /api/v1/crm/opportunities
Query Parameters:
stage(string) - Filter by stagestatus(string) - Filter by status (open, won, lost)customer_id(integer) - Filter by customerassigned_user_id(integer) - Filter by ownerpriority(string) - Filter by priorityexpected_close_date_from(date) - Close date range startexpected_close_date_to(date) - Close date range endmin_value(number) - Minimum opportunity valuemax_value(number) - Maximum opportunity valuesearch(string) - Search by name or descriptionper_page(integer) - Results per page (default: 25)page(integer) - Page numbersort_by(string) - Sort field (created_at, value, expected_close_date, probability)sort_direction(string) - Sort direction (asc, desc)includes(string) - Relationships to include (customer, lead, activities)
Example Request:
GET /api/v1/crm/opportunities?stage=proposal&min_value=50000&sort_by=expected_close_date&sort_direction=asc&includes=customerResponse (200 OK):
{
"data": [
{
"id": 890,
"name": "Acme Corp - Enterprise Platform Implementation",
"customer": {
"id": 568,
"customer_number": "CUST-000568",
"company_name": "Acme Corporation"
},
"stage": "proposal",
"value": 150000.00,
"weighted_value": 90000.00,
"probability": 60,
"expected_close_date": "2026-03-31",
"days_to_close": 104,
"age_in_days": 45,
"assigned_user": {
"id": 7,
"name": "Jane Manager"
},
"next_step": "Present proposal to steering committee",
"created_at": "2025-11-02T10:00:00Z"
}
],
"meta": {
"current_page": 1,
"per_page": 25,
"total": 47,
"last_page": 2
},
"summary": {
"total_opportunities": 47,
"total_value": 3450000.00,
"total_weighted_value": 1875000.00,
"average_deal_size": 73404.00,
"win_rate": 42.5
}
}Viewing Opportunity Details
Endpoint: GET /api/v1/crm/opportunities/{id}
Query Parameters:
includes(string) - Relationships:customer,lead,activities,campaign
Example:
GET /api/v1/crm/opportunities/890?includes=customer,activitiesResponse (200 OK):
{
"data": {
"id": 890,
"name": "Acme Corp - Enterprise Platform Implementation",
"description": "Full platform deployment for 500 users across 5 departments.",
"customer": {
"id": 568,
"customer_number": "CUST-000568",
"company_name": "Acme Corporation",
"email": "contact@acmecorp.com"
},
"lead": {
"id": 1234,
"email": "contact@acmecorp.com",
"source": "referral"
},
"stage": "proposal",
"value": 150000.00,
"expected_revenue": 150000.00,
"weighted_value": 90000.00,
"currency": "USD",
"probability": 60,
"expected_close_date": "2026-03-31",
"days_to_close": 104,
"age_in_days": 45,
"stage_duration": 12,
"source": "lead_conversion",
"priority": "high",
"assigned_user": {
"id": 7,
"name": "Jane Manager",
"email": "jane@yourcompany.com"
},
"territory": "North America - Enterprise",
"competitor": "Competitor X",
"decision_maker": "Jane Smith, CTO",
"budget_confirmed": true,
"authority_confirmed": true,
"need_confirmed": true,
"timeline_confirmed": true,
"bant_score": 4,
"health_score": 78,
"next_step": "Present proposal to steering committee on Dec 20",
"discovery_notes": "Detailed requirements gathered. Integration with SAP and Salesforce required.",
"proposal_notes": "Proposal delivered Dec 15. Well received. Questions on implementation timeline.",
"demo_date": "2025-11-20",
"proposal_date": "2025-12-15",
"tags": ["enterprise", "integration", "professional-services"],
"activities": [
{
"id": 2001,
"type": "meeting",
"subject": "Proposal Presentation",
"status": "completed",
"completed_at": "2025-12-15T14:00:00Z"
}
],
"created_at": "2025-11-02T10:00:00Z",
"updated_at": "2025-12-15T16:00:00Z"
}
}Updating Opportunities
Endpoint: PUT /api/v1/crm/opportunities/{id} or PATCH /api/v1/crm/opportunities/{id}
Request Body (partial update):
{
"value": 175000.00,
"probability": 65,
"expected_close_date": "2026-03-25",
"timeline_confirmed": true,
"next_step": "Schedule contract review with legal team",
"proposal_notes": "Proposal approved by steering committee. Requested additional professional services for data migration. Updated value to $175K.",
"custom_fields": {
"services_hours": 200,
"migration_required": true
}
}Response (200 OK):
{
"message": "Opportunity updated successfully",
"data": {
"id": 890,
"value": 175000.00,
"weighted_value": 113750.00,
"probability": 65,
"expected_close_date": "2026-03-25",
"updated_at": "2025-12-17T21:00:00Z"
}
}Stage Management
Update to Specific Stage
Endpoint: PATCH /api/v1/crm/opportunities/{opportunityId}/stage
Request Body:
{
"stage": "negotiation",
"notes": "Proposal approved. Moving to negotiation phase. Discussing pricing and implementation timeline."
}Response (200 OK):
{
"message": "Opportunity stage updated successfully",
"data": {
"id": 890,
"stage": "negotiation",
"probability": 75,
"previous_stage": "proposal",
"stage_changed_at": "2025-12-17T21:30:00Z",
"updated_at": "2025-12-17T21:30:00Z"
}
}Move to Next Stage
Endpoint: POST /api/v1/crm/opportunities/{opportunityId}/stage/next
Request Body (optional):
{
"notes": "Discovery completed. All requirements documented. Moving to proposal stage."
}Response (200 OK):
{
"message": "Opportunity advanced to next stage successfully",
"data": {
"id": 890,
"stage": "proposal",
"probability": 60,
"previous_stage": "needs_analysis",
"updated_at": "2025-12-17T21:45:00Z"
}
}Move to Previous Stage
Endpoint: POST /api/v1/crm/opportunities/{opportunityId}/stage/previous
Request Body:
{
"reason": "Customer requested additional discovery on integration requirements",
"notes": "Moving back to needs analysis to address newly identified integration complexities."
}Response (200 OK):
{
"message": "Opportunity moved to previous stage successfully",
"data": {
"id": 890,
"stage": "needs_analysis",
"probability": 40,
"previous_stage": "proposal",
"updated_at": "2025-12-17T22:00:00Z"
}
}Moving Backward
Moving opportunities backward in the pipeline should be rare and documented. It often indicates issues that need addressing or insufficient qualification in earlier stages.
Closing Opportunities
Mark as Won
Endpoint: POST /api/v1/crm/opportunities/{opportunityId}/win
Request Body:
{
"close_reason": "Proposal accepted. Contract signed. Implementation starts January 2026.",
"actual_value": 175000.00,
"close_date": "2025-12-18"
}Response (200 OK):
{
"message": "Opportunity marked as won",
"data": {
"id": 890,
"stage": "won",
"probability": 100,
"actual_close_date": "2025-12-18T00:00:00Z",
"expected_close_date": "2026-03-25",
"days_early": 97,
"value": 175000.00,
"sales_cycle_days": 46,
"close_reason": "Proposal accepted. Contract signed. Implementation starts January 2026.",
"won_at": "2025-12-18T10:00:00Z"
}
}Mark as Lost
Endpoint: POST /api/v1/crm/opportunities/{opportunityId}/lose
Request Body:
{
"loss_reason": "price",
"competitor": "Competitor X",
"loss_notes": "Lost to Competitor X on price. Customer chose lower-priced option despite our superior features. Price was 30% lower. Did not value professional services component.",
"lessons_learned": "Need to better articulate ROI value vs. upfront cost. Consider flexible pricing options for price-sensitive customers."
}Loss Reason Values:
price- Lost on price/budgetcompetitor- Lost to competitorno_decision- Customer chose not to proceedtiming- Timing not rightlack_of_features- Missing required featuresinternal_champion_left- Champion left organizationbudget_cuts- Budget was cut/frozenother- Other reason (specify in notes)
Response (200 OK):
{
"message": "Opportunity marked as lost",
"data": {
"id": 890,
"stage": "lost",
"probability": 0,
"actual_close_date": "2025-12-18T00:00:00Z",
"loss_reason": "price",
"competitor": "Competitor X",
"sales_cycle_days": 46,
"close_reason": "Lost to Competitor X on price. Customer chose lower-priced option despite our superior features.",
"lost_at": "2025-12-18T11:00:00Z"
}
}Assigning Opportunities
Endpoint: POST /api/v1/crm/opportunities/{opportunityId}/assign
Request Body:
{
"user_id": 9,
"reason": "Reassigning to enterprise specialist for complex technical requirements",
"notify": true
}Response (200 OK):
{
"message": "Opportunity assigned successfully",
"data": {
"id": 890,
"assigned_user_id": 9,
"assigned_user": {
"id": 9,
"name": "Robert Enterprise",
"email": "robert@yourcompany.com"
},
"previous_owner_id": 7,
"assigned_at": "2025-12-17T22:30:00Z"
}
}Pipeline Analytics
Get Pipeline Data
Endpoint: GET /api/v1/crm/opportunities/pipeline-data
Query Parameters:
user_id(integer) - Filter by opportunity ownerdate_range(string) - Time period (this_quarter, next_quarter, this_year)
Response (200 OK):
{
"data": {
"by_stage": [
{
"stage": "prospecting",
"count": 15,
"total_value": 450000.00,
"weighted_value": 45000.00,
"average_deal_size": 30000.00
},
{
"stage": "qualification",
"count": 12,
"total_value": 780000.00,
"weighted_value": 195000.00,
"average_deal_size": 65000.00
},
{
"stage": "needs_analysis",
"count": 8,
"total_value": 920000.00,
"weighted_value": 368000.00,
"average_deal_size": 115000.00
},
{
"stage": "proposal",
"count": 6,
"total_value": 1200000.00,
"weighted_value": 720000.00,
"average_deal_size": 200000.00
},
{
"stage": "negotiation",
"count": 4,
"total_value": 850000.00,
"weighted_value": 637500.00,
"average_deal_size": 212500.00
},
{
"stage": "verbal_commitment",
"count": 2,
"total_value": 400000.00,
"weighted_value": 360000.00,
"average_deal_size": 200000.00
}
],
"summary": {
"total_opportunities": 47,
"total_pipeline_value": 4600000.00,
"total_weighted_value": 2325500.00,
"average_deal_size": 97872.00,
"win_rate": 45.5,
"average_sales_cycle_days": 67
},
"forecast": {
"commit": 360000.00,
"best_case": 1997500.00,
"pipeline": 2325500.00
}
}
}Get Sales Forecast
Endpoint: GET /api/v1/crm/opportunities/forecast
Query Parameters:
quarter(string) - Q1, Q2, Q3, Q4year(integer) - Yearuser_id(integer) - Specific user forecast
Response (200 OK):
{
"data": {
"period": "Q1 2026",
"forecast_categories": {
"commit": {
"description": "90%+ probability, closing this period",
"count": 2,
"value": 360000.00
},
"best_case": {
"description": "60%+ probability, likely to close",
"count": 8,
"value": 1637500.00
},
"pipeline": {
"description": "All opportunities in pipeline",
"count": 47,
"value": 2325500.00
},
"at_risk": {
"description": "Overdue or stalled opportunities",
"count": 5,
"value": 425000.00
}
},
"trends": {
"vs_last_quarter": {
"change_percentage": 15.5,
"change_value": 312000.00
},
"vs_same_quarter_last_year": {
"change_percentage": 22.3,
"change_value": 412000.00
}
},
"confidence_level": "medium",
"notes": "Pipeline healthy. 15% growth over last quarter. Enterprise segment showing strong momentum."
}
}Business Scenarios
Scenario 1: Moving Deal Through Pipeline
Context: Enterprise opportunity progressing from prospecting to close
Workflow:
# Stage 1: Create opportunity (Prospecting)
POST /api/v1/crm/opportunities
{
"name": "BigCorp - Platform Deployment",
"customer_id": 568,
"value": 200000.00,
"expected_close_date": "2026-04-30",
"stage": "prospecting",
"next_step": "Schedule discovery call"
}
# Stage 2: Move to Qualification after initial calls
POST /api/v1/crm/opportunities/891/stage/next
{
"notes": "Completed discovery call. Qualified using BANT. Budget confirmed $200K. CTO is decision maker. Clear need for integration platform. Timeline Q1 2026."
}
# Update BANT status
PATCH /api/v1/crm/opportunities/891
{
"budget_confirmed": true,
"authority_confirmed": true,
"need_confirmed": true,
"timeline_confirmed": true,
"next_step": "Conduct detailed technical discovery"
}
# Stage 3: Move to Needs Analysis
POST /api/v1/crm/opportunities/891/stage/next
{
"notes": "Full technical discovery completed. Requirements documented. Solution architecture defined."
}
# Stage 4: Move to Proposal
POST /api/v1/crm/opportunities/891/stage/next
{
"notes": "Proposal created and sent. Includes technical solution, pricing, implementation timeline. Presenting Dec 22."
}
# Record proposal delivery
PATCH /api/v1/crm/opportunities/891
{
"proposal_date": "2025-12-20",
"proposal_notes": "Comprehensive proposal delivered. Includes 3 pricing tiers, implementation plan, ROI analysis.",
"next_step": "Present proposal to stakeholder committee Dec 22"
}
# Stage 5: Move to Negotiation
POST /api/v1/crm/opportunities/891/stage/next
{
"notes": "Proposal approved. Negotiating final pricing and implementation timeline. Customer requested 10% discount."
}
# Stage 6: Verbal Commitment received
POST /api/v1/crm/opportunities/891/stage/next
{
"notes": "Verbal commitment received. Agreed on $185K (reduced from $200K). Finalizing contract. Expecting signature by Dec 28."
}
# Stage 7: Close as Won
POST /api/v1/crm/opportunities/891/win
{
"close_reason": "Contract signed. $185K deal. Implementation starts January 15, 2026.",
"actual_value": 185000.00,
"close_date": "2025-12-28"
}Scenario 2: Handling Stalled Opportunity
Context: Opportunity stuck in Proposal stage for 45 days
Workflow:
# 1. Identify stalled opportunity
GET /api/v1/crm/opportunities?stage=proposal&days_in_stage_min=30
# 2. Review opportunity details
GET /api/v1/crm/opportunities/892
# Findings: No activity in 20 days, no response to follow-ups
# 3. Create re-engagement activity
POST /api/v1/crm/activities
{
"type": "call",
"subject": "Re-engage Stalled Opportunity - Proposal Follow-up",
"opportunity_id": 892,
"priority": "high",
"scheduled_at": "2025-12-19T10:00:00Z",
"notes": "No response to proposal for 20 days. Need to understand if still interested or if timeline changed."
}
# 4. After call, determine next action
# Option A: Customer still interested, just delayed
PATCH /api/v1/crm/opportunities/892
{
"expected_close_date": "2026-05-31",
"probability": 50,
"next_step": "Follow up in January after budget finalization",
"notes": "Customer confirmed still interested. Budget approval delayed to Q1. Staying in proposal stage but adjusting timeline."
}
# Option B: Customer not responsive, move to On Hold
PATCH /api/v1/crm/opportunities/892/stage
{
"stage": "on_hold",
"notes": "Unable to reach decision maker. Putting on hold. Will re-engage in 30 days."
}
# Option C: Customer went with competitor
POST /api/v1/crm/opportunities/892/lose
{
"loss_reason": "competitor",
"competitor": "Competitor Y",
"loss_notes": "Lost to Competitor Y. Customer felt their solution better aligned with legacy systems. Competitor offered free migration services which we did not.",
"lessons_learned": "Need to include migration services in enterprise proposals. Legacy integration is key buying criterion."
}Scenario 3: Bulk Pipeline Cleanup
Context: End of quarter, clean up stale opportunities
Workflow:
# 1. Get overdue opportunities
GET /api/v1/crm/opportunities?overdue=true&per_page=100
# 2. Get opportunities with no activity in 60+ days
GET /api/v1/crm/opportunities?last_activity_days_ago_min=60&stage!=won,lost
# 3. Bulk update expected close dates
POST /api/v1/crm/opportunities/bulk-actions
{
"action": "update_close_date",
"opportunity_ids": [893, 894, 895, 896],
"parameters": {
"expected_close_date": "2026-06-30"
}
}
# 4. Close lost opportunities that are truly dead
POST /api/v1/crm/opportunities/bulk-actions
{
"action": "mark_lost",
"opportunity_ids": [897, 898],
"parameters": {
"loss_reason": "no_decision",
"loss_notes": "Customer unresponsive for 90+ days. No longer pursuing."
}
}
# 5. Move stalled deals to On Hold
POST /api/v1/crm/opportunities/bulk-actions
{
"action": "update_stage",
"opportunity_ids": [899, 900, 901],
"parameters": {
"stage": "on_hold",
"notes": "Pausing these opportunities. Will re-engage next quarter."
}
}Best Practices
1. Maintain Pipeline Hygiene
Weekly Reviews:
- Update opportunity stages based on activity
- Adjust close dates for realistic forecasting
- Close lost opportunities promptly
- Add notes after every significant interaction
Monthly Cleanup:
- Review stalled opportunities (30+ days no activity)
- Update or close opportunities with unrealistic close dates
- Reassign opportunities if owner has left
- Remove duplicate opportunities
2. Use Probability Correctly
Follow Stage Guidelines:
- Let system set probability based on stage
- Only override with valid reason
- Document why probability differs from stage default
- Avoid inflating probabilities for forecast pressure
Realistic Assessment:
- 90%+ probability = signed contract pending
- 75% probability = verbal commitment received
- <40% probability = early stage, highly uncertain
3. Document Everything
Required Documentation:
- Notes after every call/meeting
- Reasons for stage changes
- Next steps clearly defined
- Decision makers and influencers
- Competitor intelligence
- Technical requirements
Use Custom Fields:
- Implementation complexity
- User count
- Department involvement
- Integration requirements
4. Track BANT Throughout
Update BANT Status:
- Set flags as each criterion is confirmed
- Re-verify if opportunity stalls
- Use BANT score (0-4) to prioritize
- Don't advance to Proposal without BANT confirmation
5. Forecast Accurately
Commit Category:
- Only opportunities 90%+ probability
- Verbal commitment or better
- Closing this quarter/period
- No known blockers
Best Case Category:
- Opportunities 60%+ probability
- Proposal or Negotiation stage
- Strong customer engagement
- Realistic close date
6. Learn from Losses
Loss Analysis:
- Document loss reason accurately
- Capture competitor insights
- Record lessons learned
- Share insights with team
- Adjust sales process based on patterns
Troubleshooting
Cannot Advance Stage
Error: "Invalid stage transition"
Cause: Attempting invalid progression (e.g., skipping stages)
Solution:
- Follow valid stage progression
- Use the provided stage transition paths
- Document reason if moving backward
- Contact admin if stage model needs adjustment
Opportunity Stuck in Stage
Issue: Opportunity not progressing
Diagnosis:
- No recent activities logged
- No response from customer
- Missing required information
- Awaiting external dependency
Actions:
- Schedule re-engagement call
- Update close date if delayed
- Move to On Hold if appropriate
- Consider marking as lost if truly dead
Forecast Accuracy Low
Issue: Consistently missing forecast
Analysis:
- Are probabilities realistic?
- Are close dates accurate?
- Are dead deals being closed?
- Are stages being updated promptly?
Improvements:
- Implement weekly pipeline reviews
- Adjust probability methodology
- Train team on forecasting discipline
- Use historical win rates to calibrate
Related Documentation
- Lead Management - Lead qualification and scoring
- Lead Conversion - Converting leads to opportunities
- Customer Management - Customer relationship management
- Activity Management - Tracking opportunity activities