Account Risk Early Warning
Retaining existing customers is more cost-effective than acquiring new ones. This skill monitors key accounts for early warning signals that indicate potential churn or relationship issues, enabling proactive intervention before problems escalate.
Instructions
Step 1: Determine Scope
When user asks "Which of my top accounts are showing warning signs?":
1.1 Define Account Set:
Options: A) All active accounts owned by user B) Specific account list (e.g., enterprise tier) C) Accounts with revenue above threshold D) Accounts up for renewal in next X months
1.2 Query Target Accounts:
SELECT accountid, name, revenue, numberofemployees, industrycode, createdon, ownerid, customertypecode, territoryid, openrevenue, openrevenue_date FROM account -- Note: openrevenue and openrevenue_date are rollup fields that may not exist in all orgs. -- If absent, calculate open pipeline value by querying the opportunity table directly. WHERE statecode = 0 AND ownerid = '[current_user_id]' -- or specific criteria ORDER BY revenue DESC
Step 2: Analyze Risk Signals for Each Account
Important: Dataverse SQL Limitations Dataverse SQL does NOT support: subqueries, DATEADD(), GETUTCDATE(), HAVING, DISTINCT, UNION, CASE statements. Use separate queries and calculate date filters programmatically (e.g., calculate '2025-09-01' for 6 months ago).
2.1 Activity Trend Analysis Query recent activities for each account (run separately per account):
SELECT activityid, activitytypecode, createdon, statecode FROM activitypointer WHERE regardingobjectid = '[accountid]' AND createdon > '2025-09-01' ORDER BY createdon DESC
Calculate Activity Metrics:
For each account: - Total activities (last 6 months) - Activities per month trend - Activity types breakdown - Days since last activity - Comparison to account's historical average
Activity Risk Indicators:
| Signal | Warning | Critical |
|---|---|---|
| Days Since Last Activity | 30+ days | 60+ days |
| Month-over-Month Decline | 25%+ decline | 50%+ decline |
| No Meetings/Calls | 45+ days | 90+ days |
| Only Automated Emails | 30+ days | 60+ days |
2.2 Support Case Pattern Analysis Query recent cases (run per account, calculate date filter programmatically):
SELECT incidentid, title, createdon, prioritycode, severitycode, statecode, statuscode, caseorigincode, customersatisfactioncode, msdyn_casesentiment, escalatedon FROM incident WHERE customerid = '[accountid]' AND createdon > '2025-09-01' ORDER BY createdon DESC
Calculate Case Metrics:
For each account: - Total cases (last 6 months) - Cases per month trend - Case severity distribution - Average resolution time - Escalation count - Customer satisfaction scores (if available) - Sentiment analysis (msdyn_casesentiment)
Case Risk Indicators:
| Signal | Warning | Critical |
|---|---|---|
| Case Volume Increase | 50%+ increase | 100%+ increase |
| High Severity Cases | 2+ in 30 days | 5+ in 30 days |
| Escalated Cases | 1 in 60 days | 2+ in 60 days |
| Negative Sentiment | Score 9 (Slightly negative) | Score 7-8 (Very negative / Negative) |
| Low Satisfaction | Score 2-3 | Score 1 (Very Dissatisfied) |
| Unresolved Cases | 3+ open > 7 days | 5+ open > 14 days |
2.3 Opportunity Velocity Analysis Query opportunity history (per account, calculate date filter programmatically):
SELECT opportunityid, name, estimatedvalue, actualvalue, statecode, statuscode, createdon, actualclosedate, salesstage, msdyn_forecastcategory FROM opportunity WHERE accountid = '[accountid]' AND createdon > '2024-03-01' ORDER BY createdon DESC
Calculate Opportunity Metrics:
For each account: - New opportunities (last 6 months vs prior 6 months) - Win rate trend - Average deal size trend - Pipeline coverage - Time since last won deal - Lost opportunities (recent)
Opportunity Risk Indicators:
| Signal | Warning | Critical |
|---|---|---|
| No New Opportunities | 90+ days | 180+ days |
| Declining Win Rate | 20%+ decline | 50%+ decline |
| Declining Deal Size | 25%+ decline | 50%+ decline |
| Recent Lost Deals | 1 in 60 days | 2+ in 60 days |
| Stalled Pipeline | 60+ days no movement | 90+ days |
2.4 Engagement Pattern Analysis Analyze contact engagement:
SELECT c.contactid, c.fullname, c.jobtitle, c.accountrolecode FROM contact c WHERE c.accountid IN ([target account ids]) AND c.statecode = 0 SELECT a.regardingobjectid, COUNT(*) as activity_count, MAX(a.createdon) as last_activity FROM activitypointer a JOIN contact c ON a.regardingobjectid = c.contactid WHERE c.accountid IN ([target account ids]) AND a.createdon >= '[6_months_ago]' GROUP BY a.regardingobjectid
Engagement Risk Indicators:
| Signal | Warning | Critical |
|---|---|---|
| Key Contact Disengaged | 45+ days no response | 90+ days |
| Champion Gone Dark | 30+ days | 60+ days |
| Executive Engagement Drop | 50%+ decline | 75%+ decline |
| New Decision Maker | Not yet engaged | 60+ days not engaged |
| Contact Left Company | Detected | Champion left |
2.5 Relationship Signals from Notes Analyze annotations and activity descriptions:
SELECT a.objectid, a.subject, a.notetext, a.createdon FROM annotation a WHERE a.objecttypecode = 'account' AND a.objectid IN ([target account ids]) AND a.createdon >= '[6_months_ago]' ORDER BY a.createdon DESC
Keyword Detection: Look for risk keywords in notes:
- Negative: "unhappy", "frustrated", "dissatisfied", "complaint", "issue", "problem", "leaving", "cancel", "competitor"
- Competitive: "evaluating alternatives", "RFP", "comparing options", "other vendors"
- Organizational: "budget cut", "freeze", "layoffs", "restructuring", "merger", "acquisition"
- Turnover: "leaving company", "new role", "replacement", "transition"
2.6 Renewal and Contract Signals If contract/renewal data available:
Query opportunities or custom entities for: - Upcoming renewal dates - Contract end dates - Renewal discussions (or lack thereof)
Renewal Risk Indicators:
| Signal | Warning | Critical |
|---|---|---|
| Renewal in 90 days | No discussion started | Negative feedback received |
| Renewal in 60 days | No commitment | Competitor being evaluated |
| Renewal in 30 days | Not verbal confirmed | At risk / declining |
Step 3: Calculate Composite Risk Score
Risk Score Model (0-100, higher = more risk):
| Risk Category | Weight | Max Points |
|---|---|---|
| Activity Decline | 20% | 20 |
| Support Case Patterns | 25% | 25 |
| Opportunity Velocity | 20% | 20 |
| Engagement Patterns | 20% | 20 |
| Relationship Signals | 15% | 15 |
Score Interpretation:
- 0-25: Healthy - No significant risk signals
- 26-50: Monitor - Early warning signs, watch closely
- 51-75: At Risk - Multiple warning signals, intervention needed
- 76-100: Critical - Immediate action required
Step 4: Prioritize Intervention Targets
Sort accounts by:
- Risk Score (highest first)
- Revenue Impact (larger accounts prioritized)
- Renewal Proximity (sooner renewals first)
- Relationship Investment (longer tenure/more history)
Calculate Priority Score:
priority = risk_score * 0.5 + revenue_weight * 0.3 + renewal_urgency * 0.2 Where: - risk_score: 0-100 from Step 3 - revenue_weight: Normalized account revenue - renewal_urgency: Days until renewal (inverted scale)
Step 5: Generate Risk Report
Output Format:
ACCOUNT RISK EARLY WARNING REPORT ════════════════════════════════════════════════════ Generated: [Date] Scope: [User]'s Accounts Accounts Analyzed: [N] ════════════════════════════════════════════════════ RISK SUMMARY ════════════════════════════════════════════════════ Critical Risk (76-100): [N] accounts $[revenue at risk] At Risk (51-75): [N] accounts $[revenue at risk] Monitor (26-50): [N] accounts $[revenue at risk] Healthy (0-25): [N] accounts $[revenue value] TOTAL REVENUE AT RISK: $[sum of Critical + At Risk] ════════════════════════════════════════════════════ PRIORITY INTERVENTION LIST ════════════════════════════════════════════════════ 1. 🔴 CONTOSO CORPORATION Risk Score: 85/100 (Critical) Annual Revenue: $500,000 Renewal: 45 days ───────────────────────────────────────────────── WARNING SIGNALS: ⚠️ Activity Decline: 67% fewer touchpoints vs prior quarter ⚠️ Support Cases: 8 cases in 30 days (up 300% from average) ⚠️ Escalation: 2 escalated cases in past month ⚠️ Sentiment: Case sentiment trending negative (avg 7.5) ⚠️ Competitor: "Evaluating alternatives" mentioned in notes ⚠️ Contact: VP Champion hasn't responded in 45 days DETAILED ANALYSIS: Activity Trend: • 6 months ago: 12 activities/month • Current: 4 activities/month • Trend: ↓ 67% decline Support Cases: • Total (6 mo): 15 cases • Last 30 days: 8 cases (spike) • High Severity: 3 cases • Avg Resolution: 5.2 days (above SLA) Opportunity Status: • No new opportunities in 120 days • Last won deal: 8 months ago • Pipeline: $0 (no active deals) Key Contacts: • Sarah Chen (VP Ops) - Last contact: 45 days ago ⚠️ • John Smith (IT Dir) - Last contact: 12 days ago ✓ RECOMMENDED INTERVENTIONS: Priority 1 (Immediate): 📞 Executive outreach from sales leadership to Sarah Chen • Acknowledge support issues • Request relationship review meeting • Bring solutions, not sales pitch Priority 2 (This Week): 📋 Support case review with CS team • Identify root cause of case spike • Escalate to product/engineering if needed • Prepare remediation plan Priority 3 (Within 2 Weeks): 📅 Renewal discussion meeting • Don't wait - engage on renewal now • Address concerns before they finalize decision • Consider retention incentives if needed ───────────────────────────────────────────────── 2. 🟠 FABRIKAM INDUSTRIES Risk Score: 62/100 (At Risk) Annual Revenue: $250,000 Renewal: 90 days ───────────────────────────────────────────────── WARNING SIGNALS: ⚠️ Champion Left: Primary contact left company 30 days ago ⚠️ New Decision Maker: Replacement not yet engaged ⚠️ Activity: 45 days since meaningful engagement RECOMMENDED INTERVENTIONS: Priority 1: Identify and engage new decision maker • Research LinkedIn for replacement • Get warm intro from remaining contacts • Schedule introductory meeting [Continue for additional at-risk accounts...]
Step 6: Create Intervention Tasks
For each high-priority account, offer to create:
Use create_record with tablename: task { "subject": "⚠️ Risk Intervention: [Account Name]", "description": "Risk Score: [X]/100\n\nKey Warning Signals:\n- [Signal 1]\n- [Signal 2]\n\nRecommended Actions:\n1. [Action 1]\n2. [Action 2]", "regardingobjectid": "[accountid]", "scheduledend": "[today or tomorrow]", "prioritycode": 1 (High) }
Add note to account record:
Use create_record with tablename: annotation { "subject": "Risk Assessment - [Date]", "notetext": "Account flagged as [Risk Level].\n\nWarning Signals:\n[Details]\n\nIntervention Plan:\n[Actions]", "objectid": "[accountid]", "objecttypecode": "account" }
Dataverse Tables Used
| Table | Purpose |
|---|---|
account | Primary entity for risk analysis |
activitypointer | Activity trend analysis |
phonecall | Engagement tracking |
appointment | Meeting frequency |
email | Communication patterns |
incident | Support case patterns |
opportunity | Revenue velocity |
contact | Stakeholder engagement |
annotation | Notes for signal detection |
task | Create intervention tasks |
Key Fields Reference
account:
revenue(MONEY) - Account value for prioritizationownerid(OWNER) - Account owner for filteringcreatedon(DATETIME) - Tenure calculationcustomertypecode(CHOICE) - Relationship typeopenrevenue(MONEY) - Total open pipeline value (rollup field; availability depends on org configuration)msdyn_accountkpiid(LOOKUP → msdyn_accountkpiitem) - Relationship analytics KPIstatecode(STATE) - Active(0), Inactive(1)
msdyn_accountkpiitem (Sales Insights - Relationship Analytics):
msdyn_relationshiphealthscorevalue(INT) - Health score (0-100)msdyn_relationshiphealthscorestate(CHOICE) - Good(0), Fair(1), Poor(2)msdyn_relationshiphealthtrend(CHOICE) - Improving(0), Steady(1), Declining(2), Not enough info(3)msdyn_emailssent(INT) - Outgoing emails countmsdyn_emailsreceived(INT) - Incoming emails countmsdyn_phonecallsmade(INT) - Outbound calls countmsdyn_phonecallsreceived(INT) - Inbound calls countmsdyn_meetingssent(INT) - Meetings scheduled countmsdyn_lastactivitybyteam(DATETIME) - Last team outreachmsdyn_nextactivitybyteam(DATETIME) - Next scheduled activitymsdyn_facetimewithcustomer(DURATION) - Total meeting timemsdyn_timespentbyteam(DURATION) - Total time investedmsdyn_averagefirstresponsetimebyusinhrs(FLOAT) - Avg response time (hours)
incident:
prioritycode(CHOICE) - High(1), Normal(2), Low(3)severitycode(CHOICE) - Severity levelcasetypecode(CHOICE) - Question(1), Problem(2), Request(3)caseorigincode(CHOICE) - Source channelcustomersatisfactioncode(CHOICE) - Very Dissatisfied(1), Dissatisfied(2), Neutral(3), Satisfied(4), Very Satisfied(5)msdyn_casesentiment(CHOICE) - Sentiment scale (lower = more negative): Very negative(7), Negative(8), Slightly negative(9), Neutral(10), Slightly positive(11), Positive(12), Very positive(13)escalatedon(DATETIME) - Escalation trackingstatecode(STATE) - Active(0), Resolved(1), Cancelled(2)statuscode(STATUS) - In Progress(1), On Hold(2), Waiting(3), Researching(4) [Active]; Problem Solved(5), Info Provided(1000) [Resolved]; Cancelled(6), Merged(2000) [Cancelled]
activitypointer:
activitytypecode(NVARCHAR) - Type: phonecall, email, appointment, taskcreatedon(DATETIME) - Activity dateregardingobjectid(LOOKUP) - Polymorphic link to account, contact, etc.statecode(STATE) - Open(0), Completed(1), Canceled(2), Scheduled(3-appointments)
Risk Signal Weights (Configurable)
| Signal Category | Default Weight | Adjustable Range |
|---|---|---|
| Activity Decline | 20% | 10-30% |
| Support Cases | 25% | 15-35% |
| Opportunity Velocity | 20% | 10-30% |
| Engagement Patterns | 20% | 10-30% |
| Relationship Signals | 15% | 10-25% |
Best Practices
- Early intervention wins: Act on Monitor-level risks before they become Critical
- Don't assume: Verify signals with direct customer conversation
- Cross-functional response: Involve Success, Support, and Sales in intervention
- Document everything: Track intervention actions for pattern learning
- Regular cadence: Run risk analysis weekly for proactive management
Examples
Example 1: Weekly Account Health Check
User says: "Which of my accounts are at risk?"
Actions:
- Query all active accounts owned by user
- Analyze activity trends, support cases, opportunity velocity for each
- Calculate composite risk score
- Rank accounts by risk level
Result:
ACCOUNT RISK SUMMARY Critical (2): Immediate intervention required Warning (5): Schedule check-in this week Monitor (8): Watch for changes Healthy (35): No action needed CRITICAL ACCOUNTS: 1. Contoso Ltd - Risk Score: 85/100 - 60+ days since last activity - 3 escalated support cases - Renewal in 45 days ACTION: Executive outreach immediately 2. Fabrikam Inc - Risk Score: 78/100 - Activity declined 70% vs prior quarter - Champion contact left company ACTION: Re-establish relationships
Example 2: Specific Account Health Analysis
User says: "Check the health of the Northwind account"
Actions:
- Retrieve Northwind account details
- Analyze all risk signals in depth
- Provide detailed breakdown with recommendations
Result:
NORTHWIND TRADERS - HEALTH ASSESSMENT Overall Risk: WARNING (62/100) ACTIVITY ANALYSIS: - Last interaction: 28 days ago (email) - Trend: Declining (45% fewer touchpoints vs. prior 90 days) SUPPORT ANALYSIS: - Open cases: 2 (1 high priority) - Recent escalation: Yes (3 days ago) - Sentiment: Slightly negative OPPORTUNITY ANALYSIS: - No new opportunities in 6 months - Last deal: Won 8 months ago RECOMMENDATION: Schedule customer success call to address open cases and explore expansion opportunities.
Example 3: Renewal Risk Analysis
User says: "Show me accounts with renewals coming up that are at risk"
Actions:
- Filter accounts with renewals in next 90 days
- Cross-reference with risk signals
- Prioritize by revenue and risk score
Result:
AT-RISK RENEWALS (Next 90 Days): 1. Alpine Ski House - $150K ARR - Renews in 30 days Risk: High engagement drop + unresolved escalation 2. Tailspin Toys - $80K ARR - Renews in 60 days Risk: Budget freeze mentioned in recent call notes
Troubleshooting
Error: No risk data available
Cause: Sales Insights or Relationship Analytics not enabled Solution:
- Fall back to activity count analysis
- Use support case data as primary signal
- Calculate manual engagement score from activitypointer
Error: Too many false positives
Cause: Thresholds too sensitive for organization's engagement patterns Solution:
- Adjust activity threshold based on account tier
- Consider industry-specific baselines
- Weight signals based on historical churn correlation
Error: Missing support case data
Cause: Customer service not using Dynamics 365 for cases Solution:
- Focus on activity and opportunity signals
- Consider integrating external support data
- Use activity notes for sentiment analysis


