ApexCloud Retention Operations — Reusable Skill
Overview
This skill covers the ApexCloud Retention Operations API for customer success workflows: renewal risk scoring, QBR metrics compilation, receivables/pipeline reviews, churn model validation, and retention action boards. Every task follows a fetch → compute → fill-template → return-JSON pattern. Output is always a single JSON object with no markdown wrapping.
API Fundamentals
Base URL
Use the remote URL from environment_access.md. Never use localhost, 127.0.0.1, or URLs from task prompts unless they match the remote URL.
Endpoint Reference
| Endpoint |
Method |
Key Query Params |
Returns |
/api/accounts/<id> |
GET |
— |
Account profile: account_id, legal_name, display_name, account_aliases[], billing_arr_current, crm_arr, contract_tenure_months, csm_owner, lifecycle_status, product_plan, region, renewal_date, segment |
/api/accounts/<id>/metrics |
GET |
start=YYYY-MM, end=YYYY-MM |
Monthly metrics array: month, recognized_revenue, sla_compliance (pct), support_ticket_count, nps_score (nullable), product_usage, active_seats, survey_status |
/api/accounts/<id>/tickets |
GET |
start=YYYY-MM-DD, end=YYYY-MM-DD |
Support tickets array: ticket_id, created_date, status, severity, is_spam, is_duplicate, first_response_sla_met, resolution_sla_met, product_area |
/api/accounts/<id>/nps |
GET |
start=YYYY-MM-DD, end=YYYY-MM-DD |
NPS responses array: response_date, score, survey_channel, retracted |
/api/finance/ar-aging |
GET |
as_of=YYYY-MM-DD |
A/R aging array: customer_name, aging_id, current, 1_30, 31_60, 61_90, 90_plus, region, quarter |
/api/accounts |
GET |
— |
List of all accounts (44 total) with same shape as single-account endpoint |
/api/opportunities |
GET |
quarter=YYYY-QN |
Pipeline opportunities: account_id, amount, close_date, state (open/closed), stage, product_line, region |
/api/hr/summary |
GET |
quarter=YYYY-QN |
HR summaries by region: headcount, unpaid_claims_amount, unpaid_claims_count, attendance_rate, region |
/api/events/performance |
GET |
event=<name>, quarter=YYYY-QN |
Event performance: event_orders, event_revenue, product_revenue, completed_orders, cancelled_orders |
/exports/churn/train.csv |
GET |
— |
CSV: 180 rows, 19 features + target (Churn) |
/exports/churn/validation.csv |
GET |
— |
CSV: 60 rows, same schema |
/exports/churn/candidates.csv |
GET |
— |
CSV: 19 features per candidate (no target), keyed by customer_id |
Date Format Conventions
- Months:
YYYY-MM (e.g. 2026-04)
- Dates:
YYYY-MM-DD (e.g. 2026-06-30)
- Quarters:
YYYY-QN (e.g. 2026-Q2)
- Always use the exact date range from the task prompt; do not extend or shorten windows.
Data Cleaning Rules
Ticket Cleaning
Clean ticket = a ticket where ALL of the following are true:
is_spam is false
is_duplicate is false
status is NOT "cancelled"
Tickets with status: "open" ARE included in clean counts. Tickets with status: "closed" ARE included. Only "cancelled" is excluded.
Clean ticket count = count of tickets passing all three filters.
SLA Calculation
When computing SLA compliance from ticket-level data, use first_response_sla_met (not resolution_sla_met). The metrics endpoint's sla_compliance field is a separate, broader metric — check which one the task requires.
SLA % = (clean tickets with first_response_sla_met: true / total clean tickets) × 100, rounded to 1 decimal.
NPS Scoring
latest_nps = the most recent non-null nps_score in the analysis period. Check both the NPS endpoint (/nps, sorted by response_date) and the metrics endpoint (nps_score by month). If the NPS endpoint returns a score for the latest month, use it; if not, use the metrics endpoint's value. Ignore retracted: true responses.
- Monthly NPS for QBR = the
nps_score from the metrics endpoint for that month (may be null if survey_status: "missing").
A/R Overdue Balance
overdue_balance = 61_90 + 90_plus from the A/R aging record. These are the "older" aging buckets. Do NOT include 1_30 or 31_60 in the overdue balance.
A/R-to-CRM Account Linking
Match A/R customer_name to CRM accounts by checking against each account's legal_name AND all entries in account_aliases. The match must be exact (case-sensitive, whole-string).
- linked: found an exact match → set
link_status: "linked", account_id = the matched account_id
- unlinked: no exact match → set
link_status: "unlinked", account_id: null
Revenue Sources
Two ARR figures exist on the account profile:
billing_arr_current — authoritative for risk/retention tasks
crm_arr — CRM-reported ARR
For QBR monthly revenue, the source is recognized_revenue from the metrics endpoint, labeled as source crm_closed_won.
Expansion Pipeline
expansion_pipeline for an account = sum of opportunity amount values where:
state is "open" (NOT "closed")
close_date falls within the analysis period's date range
Closed Won and Closed Lost opportunities do NOT count toward expansion pipeline.
Output Precision Rules
| Data Type |
Precision |
Example |
| Currency (ARR, revenue, balances, pipeline) |
2 decimal places |
1416439.47 |
| Percentages (accuracy, win rate, SLA) |
1 decimal place |
93.3 |
| NPS scores |
Integer |
39 |
| Risk scores |
Integer (0–100) |
100 |
| Counts (tickets, accounts, headcount) |
Integer |
13 |
| Churn probabilities |
3 decimal places |
0.102 |
Controlled Vocabularies (Enums)
Never invent new enum values. Use only these strings exactly as written:
risk_level
critical | high | medium | low
primary_action / outreach_action
executive_qbr | collections_followup | technical_recovery | renewal_save | nurture_monitor | no_action
reason_codes
overdue_receivable | low_tenure_high_churn | sla_degradation | nps_drop | usage_decline | renewal_window | expansion_offset | clean_billings
ticket_trend
improving (decreasing count) | worsening (increasing) | flat (unchanged)
metric_sources
crm_closed_won | support_export | sla_report | nps_survey | billing_snapshot | ar_aging | pipeline_crm | event_dashboard | hr_report
review_owner
solutions_engineering | customer_success | finance_ops
agenda_topics
partnership_overview | q2_metrics | performance_highlights | q3_initiatives | technical_recovery | commercial_expansion
accuracy_band
below_70 | 70_to_79 | 80_to_89 | 90_plus
tenure direction enums
tenure_risk_direction: negative (lower tenure → higher risk) | positive | not_assessed
tenure_coefficient_direction: negative (lower tenure → higher churn) | positive | zero
link_status
linked | unlinked
Business Rules
Risk Score Calculation
Risk score is an integer 0–100 built from additive signals. Higher = more at-risk. Key signals and their approximate weight:
- Renewal window (renewal_date within ~90 days of assessment date) — major contributor
- Overdue receivables (overdue_balance > 0) — major contributor
- NPS drop (latest NPS substantially below account's historical or below ~40) — moderate
- SLA degradation (first_response_sla_met failures on clean tickets) — moderate
- Usage decline (product_usage trending down across months) — moderate
- Low tenure (contract_tenure_months ≤ ~24, especially with other signals) — moderate
- Expansion offset (expansion pipeline > 0 can offset risk if the account is otherwise healthy; but can also be a risk signal if paired with other concerns) — context-dependent
Rank accounts by descending risk_score. Return exactly the requested count (typically top 5 or all accounts reviewed).
Primary Action Mapping
| Dominant Signal |
Primary Action |
| Overdue balance > 0 is the foremost concern |
collections_followup |
| SLA failures + NPS drops + usage decline dominate |
technical_recovery |
| In renewal window with moderate concerns |
renewal_save |
| Strategic account with complex issues |
executive_qbr |
| Low risk, clean bills, no urgent issues |
nurture_monitor |
| Minimal risk, no active concerns |
no_action |
When multiple signals compete, prioritize: overdue → SLA/NPS degradation → renewal timing → expansion context.
Follow-up Due Dates
no_action accounts get next_touch_due_date: null
- All other actions get a due date as specified in the task prompt. If not specified, derive reasonable defaults.
Reason Codes Assembly
Assign reason codes cumulatively — an account can have many. Rules:
overdue_receivable ↔ overdue_balance > 0
low_tenure_high_churn ↔ contract_tenure_months ≤ 24 (or task-specific threshold) AND other risk signals present
sla_degradation ↔ one or more SLA misses on clean tickets
nps_drop ↔ latest NPS is low (<50) or declined from previous period
usage_decline ↔ product_usage trending downward across months
renewal_window ↔ renewal_date is within the upcoming ~90 days
expansion_offset ↔ expansion_pipeline > 0
clean_billings ↔ overdue_balance == 0 AND no billing concerns
Portfolio / Segment Summaries
- accounts_reviewed: total count of accounts evaluated (not just top N)
- critical_or_high_count: count of accounts with risk_level
critical or high among ALL reviewed accounts
- arr_at_risk: sum of
current_arr for all reviewed accounts whose risk_level is NOT low (i.e., critical + high + medium)
- collections_count: count of accounts (in the returned top N) with
primary_action: "collections_followup"
- technical_recovery_count: count of accounts (in the returned top N) with
primary_action: "technical_recovery"
- net_revenue_exposure (when present):
arr_at_risk - open_expansion_pipeline
- linked_followup_count: count of overdue_followups with
link_status: "linked"
- unlinked_followup_count: count of overdue_followups with
link_status: "unlinked"
- strategic_accounts: count of reviewed accounts with
segment: "Strategic"
- enterprise_accounts: count of reviewed accounts with
segment: "Enterprise"
- open_expansion_pipeline: sum of all
expansion_pipeline values across reviewed accounts
Pipeline Summary
- won_count / won_revenue: opportunities with
state: "closed" AND stage ending in "Won"
- lost_count: opportunities with
state: "closed" AND stage ending in "Lost"
- open_count / open_pipeline: opportunities with
state: "open"
- win_rate_pct:
won_count / (won_count + lost_count) × 100, to 1 decimal
- top_open_product_line: the
product_line with the highest total amount among open opportunities
QBR Highlights
- average_revenue: mean of the 3 monthly revenue values, 2 decimals
- peak_revenue_month: month with highest revenue
- max_sla_month / max_sla_pct: month with highest SLA %; on ties, pick the earliest month chronologically
- peak_nps_month / peak_nps_score: month with highest NPS score
- ticket_trend: compare total clean tickets across months — decreasing →
improving, increasing → worsening, stable → flat
Churn Model Validation
- feature_count: count the feature columns in the training CSV (exclude
customer_id and the target column Churn)
- training_rows / validation_rows: row counts from the respective CSV files (excluding header)
- accuracy_pct: from the model evaluation, 1 decimal
- accuracy_band: map accuracy_pct to the correct band
- tenure_coefficient_direction:
negative if lower tenure → higher churn probability, positive if higher tenure → higher churn, zero if no relationship
- average_probability_top5: mean of the top 5 predicted churn probabilities, 3 decimals
- past_due_shortlist_count: among top 5, count where
InvoicePastDue = "Yes" in candidates.csv
- low_tenure_shortlist_count: among top 5, count where
tenure ≤ 24 in candidates.csv
Policy Codes
All tasks with policy_codes use the template's pipe-separated options. Select the middle value from each CODE-LOW|CODE-MID|CODE-HIGH triplet by default. The specific selection may vary based on data characteristics (e.g., which risk model version applies, which revenue source is used). Always select exactly one value per code key — never leave the pipe-separated template string.
Sorting Conventions
- Risk accounts: descending by
risk_score
- Overdue followups: ascending by
customer_name (lexicographic, case-sensitive)
- QBR metrics: ascending by
month (chronological)
- Action board: all reviewed accounts, descending by risk (highest risk first)
JSON Output Rules
- Valid JSON only — no markdown fences, no trailing commas, no comments
- null vs 0: Use
null for inapplicable/missing values (e.g., next_touch_due_date for no_action, account_id for unlinked A/R customers). Use 0/0.0 for true zero values
- Empty strings: Not used in answers; use
null or omit instead (template placeholders like "" get filled with real values or null)
- All keys from the answer template must be present in the output, even if some are
null or 0
- Controlled enum values only — never invent new labels
Workflow Pattern
For any task using this API:
- Read the answer template (
input/payloads/answer_template.json) to understand the exact output shape and enum options
- Identify the required endpoints from the task prompt's endpoint families or data-source descriptions
- Fetch all data in parallel where possible — account profiles, metrics, tickets, NPS, A/R, opportunities can all be fetched concurrently since they're independent
- Apply cleaning rules to tickets (exclude spam/duplicate/cancelled)
- Compute derived values (risk scores, SLA %, summaries, trends)
- Assemble the JSON following the template shape, precision rules, and enum vocabularies
- Validate: ensure all template keys are present, all enums are valid, precision matches rules, counts are consistent
- Return JSON only — no explanatory text
Common Pitfalls
- Using wrong ARR source: For risk/retention tasks,
current_arr comes from billing data, not CRM. Check uses_billing_arr_source and arr_source_code in the template.
- Including spam/duplicate/cancelled tickets in clean counts: Always filter to clean tickets before counting or computing SLA.
- Using resolution_sla_met instead of first_response_sla_met: SLA compliance for QBR and risk assessment is based on first-response SLA, not resolution SLA.
- Including 1_30 and 31_60 buckets in overdue_balance: Only
61_90 + 90_plus count as overdue.
- Fuzzy A/R matching: Account linking must be exact string match against
legal_name and each account_aliases entry. "Globex North Subsidiary LLC" ≠ "Globex North Subsidiary".
- Counting closed opportunities as pipeline: Only
state: "open" opportunities count toward expansion_pipeline.
- Wrong precision: Churn probabilities need 3 decimals, not 2. Currency needs exactly 2 decimals. Risk scores are integers.
- Inventing enum values: Use only the exact enum strings from the answer template.
- Not returning all accounts in action boards: When the task says "return all accounts," include every reviewed account, not just top N.
- Using localhost URLs: Always use the remote URL from
environment_access.md.
1---2name: fewshot-attempt-01-313description: ApexCloud Retention Operations — Reusable Skill4---5# ApexCloud Retention Operations — Reusable Skill67## Overview89This skill covers the ApexCloud Retention Operations API for customer success workflows: renewal risk scoring, QBR metrics compilation, receivables/pipeline reviews, churn model validation, and retention action boards. Every task follows a **fetch → compute → fill-template → return-JSON** pattern. Output is always a single JSON object with no markdown wrapping.1011---1213## API Fundamentals1415### Base URL1617Use the remote URL from `environment_access.md`. Never use `localhost`, `127.0.0.1`, or URLs from task prompts unless they match the remote URL.1819### Endpoint Reference2021| Endpoint | Method | Key Query Params | Returns |22|---|---|---|---|23| `/api/accounts/<id>` | GET | — | Account profile: `account_id`, `legal_name`, `display_name`, `account_aliases[]`, `billing_arr_current`, `crm_arr`, `contract_tenure_months`, `csm_owner`, `lifecycle_status`, `product_plan`, `region`, `renewal_date`, `segment` |24| `/api/accounts/<id>/metrics` | GET | `start=YYYY-MM`, `end=YYYY-MM` | Monthly metrics array: `month`, `recognized_revenue`, `sla_compliance` (pct), `support_ticket_count`, `nps_score` (nullable), `product_usage`, `active_seats`, `survey_status` |25| `/api/accounts/<id>/tickets` | GET | `start=YYYY-MM-DD`, `end=YYYY-MM-DD` | Support tickets array: `ticket_id`, `created_date`, `status`, `severity`, `is_spam`, `is_duplicate`, `first_response_sla_met`, `resolution_sla_met`, `product_area` |26| `/api/accounts/<id>/nps` | GET | `start=YYYY-MM-DD`, `end=YYYY-MM-DD` | NPS responses array: `response_date`, `score`, `survey_channel`, `retracted` |27| `/api/finance/ar-aging` | GET | `as_of=YYYY-MM-DD` | A/R aging array: `customer_name`, `aging_id`, `current`, `1_30`, `31_60`, `61_90`, `90_plus`, `region`, `quarter` |28| `/api/accounts` | GET | — | List of all accounts (44 total) with same shape as single-account endpoint |29| `/api/opportunities` | GET | `quarter=YYYY-QN` | Pipeline opportunities: `account_id`, `amount`, `close_date`, `state` (open/closed), `stage`, `product_line`, `region` |30| `/api/hr/summary` | GET | `quarter=YYYY-QN` | HR summaries by region: `headcount`, `unpaid_claims_amount`, `unpaid_claims_count`, `attendance_rate`, `region` |31| `/api/events/performance` | GET | `event=<name>`, `quarter=YYYY-QN` | Event performance: `event_orders`, `event_revenue`, `product_revenue`, `completed_orders`, `cancelled_orders` |32| `/exports/churn/train.csv` | GET | — | CSV: 180 rows, 19 features + target (`Churn`) |33| `/exports/churn/validation.csv` | GET | — | CSV: 60 rows, same schema |34| `/exports/churn/candidates.csv` | GET | — | CSV: 19 features per candidate (no target), keyed by `customer_id` |3536### Date Format Conventions3738- **Months**: `YYYY-MM` (e.g. `2026-04`)39- **Dates**: `YYYY-MM-DD` (e.g. `2026-06-30`)40- **Quarters**: `YYYY-QN` (e.g. `2026-Q2`)41- Always use the exact date range from the task prompt; do not extend or shorten windows.4243---4445## Data Cleaning Rules4647### Ticket Cleaning4849**Clean ticket** = a ticket where ALL of the following are true:50- `is_spam` is `false`51- `is_duplicate` is `false`52- `status` is NOT `"cancelled"`5354Tickets with `status: "open"` ARE included in clean counts. Tickets with `status: "closed"` ARE included. Only `"cancelled"` is excluded.5556**Clean ticket count** = count of tickets passing all three filters.5758### SLA Calculation5960When computing SLA compliance from ticket-level data, use `first_response_sla_met` (not `resolution_sla_met`). The metrics endpoint's `sla_compliance` field is a separate, broader metric — check which one the task requires.6162SLA % = (clean tickets with `first_response_sla_met: true` / total clean tickets) × 100, rounded to 1 decimal.6364### NPS Scoring6566- `latest_nps` = the most recent non-null `nps_score` in the analysis period. Check both the NPS endpoint (`/nps`, sorted by `response_date`) and the metrics endpoint (`nps_score` by month). If the NPS endpoint returns a score for the latest month, use it; if not, use the metrics endpoint's value. Ignore `retracted: true` responses.67- Monthly NPS for QBR = the `nps_score` from the metrics endpoint for that month (may be `null` if `survey_status: "missing"`).6869### A/R Overdue Balance7071`overdue_balance` = `61_90` + `90_plus` from the A/R aging record. These are the "older" aging buckets. Do NOT include `1_30` or `31_60` in the overdue balance.7273### A/R-to-CRM Account Linking7475Match A/R `customer_name` to CRM accounts by checking against each account's `legal_name` AND all entries in `account_aliases`. The match must be **exact** (case-sensitive, whole-string).7677- **linked**: found an exact match → set `link_status: "linked"`, `account_id` = the matched `account_id`78- **unlinked**: no exact match → set `link_status: "unlinked"`, `account_id: null`7980### Revenue Sources8182Two ARR figures exist on the account profile:83- `billing_arr_current` — authoritative for risk/retention tasks84- `crm_arr` — CRM-reported ARR8586For QBR monthly revenue, the source is `recognized_revenue` from the metrics endpoint, labeled as source `crm_closed_won`.8788### Expansion Pipeline8990`expansion_pipeline` for an account = sum of opportunity `amount` values where:91- `state` is `"open"` (NOT `"closed"`)92- `close_date` falls within the analysis period's date range9394Closed Won and Closed Lost opportunities do NOT count toward expansion pipeline.9596---9798## Output Precision Rules99100| Data Type | Precision | Example |101|---|---|---|102| Currency (ARR, revenue, balances, pipeline) | 2 decimal places | `1416439.47` |103| Percentages (accuracy, win rate, SLA) | 1 decimal place | `93.3` |104| NPS scores | Integer | `39` |105| Risk scores | Integer (0–100) | `100` |106| Counts (tickets, accounts, headcount) | Integer | `13` |107| Churn probabilities | 3 decimal places | `0.102` |108109---110111## Controlled Vocabularies (Enums)112113Never invent new enum values. Use only these strings exactly as written:114115### risk_level116`critical` | `high` | `medium` | `low`117118### primary_action / outreach_action119`executive_qbr` | `collections_followup` | `technical_recovery` | `renewal_save` | `nurture_monitor` | `no_action`120121### reason_codes122`overdue_receivable` | `low_tenure_high_churn` | `sla_degradation` | `nps_drop` | `usage_decline` | `renewal_window` | `expansion_offset` | `clean_billings`123124### ticket_trend125`improving` (decreasing count) | `worsening` (increasing) | `flat` (unchanged)126127### metric_sources128`crm_closed_won` | `support_export` | `sla_report` | `nps_survey` | `billing_snapshot` | `ar_aging` | `pipeline_crm` | `event_dashboard` | `hr_report`129130### review_owner131`solutions_engineering` | `customer_success` | `finance_ops`132133### agenda_topics134`partnership_overview` | `q2_metrics` | `performance_highlights` | `q3_initiatives` | `technical_recovery` | `commercial_expansion`135136### accuracy_band137`below_70` | `70_to_79` | `80_to_89` | `90_plus`138139### tenure direction enums140- `tenure_risk_direction`: `negative` (lower tenure → higher risk) | `positive` | `not_assessed`141- `tenure_coefficient_direction`: `negative` (lower tenure → higher churn) | `positive` | `zero`142143### link_status144`linked` | `unlinked`145146---147148## Business Rules149150### Risk Score Calculation151152Risk score is an integer 0–100 built from additive signals. Higher = more at-risk. Key signals and their approximate weight:153154- **Renewal window** (renewal_date within ~90 days of assessment date) — major contributor155- **Overdue receivables** (overdue_balance > 0) — major contributor156- **NPS drop** (latest NPS substantially below account's historical or below ~40) — moderate157- **SLA degradation** (first_response_sla_met failures on clean tickets) — moderate158- **Usage decline** (product_usage trending down across months) — moderate159- **Low tenure** (contract_tenure_months ≤ ~24, especially with other signals) — moderate160- **Expansion offset** (expansion pipeline > 0 can offset risk if the account is otherwise healthy; but can also be a risk signal if paired with other concerns) — context-dependent161162Rank accounts by descending risk_score. Return exactly the requested count (typically top 5 or all accounts reviewed).163164### Primary Action Mapping165166| Dominant Signal | Primary Action |167|---|---|168| Overdue balance > 0 is the foremost concern | `collections_followup` |169| SLA failures + NPS drops + usage decline dominate | `technical_recovery` |170| In renewal window with moderate concerns | `renewal_save` |171| Strategic account with complex issues | `executive_qbr` |172| Low risk, clean bills, no urgent issues | `nurture_monitor` |173| Minimal risk, no active concerns | `no_action` |174175When multiple signals compete, prioritize: overdue → SLA/NPS degradation → renewal timing → expansion context.176177### Follow-up Due Dates178179- `no_action` accounts get `next_touch_due_date: null`180- All other actions get a due date as specified in the task prompt. If not specified, derive reasonable defaults.181182### Reason Codes Assembly183184Assign reason codes cumulatively — an account can have many. Rules:185- `overdue_receivable` ↔ overdue_balance > 0186- `low_tenure_high_churn` ↔ contract_tenure_months ≤ 24 (or task-specific threshold) AND other risk signals present187- `sla_degradation` ↔ one or more SLA misses on clean tickets188- `nps_drop` ↔ latest NPS is low (<50) or declined from previous period189- `usage_decline` ↔ product_usage trending downward across months190- `renewal_window` ↔ renewal_date is within the upcoming ~90 days191- `expansion_offset` ↔ expansion_pipeline > 0192- `clean_billings` ↔ overdue_balance == 0 AND no billing concerns193194### Portfolio / Segment Summaries195196- **accounts_reviewed**: total count of accounts evaluated (not just top N)197- **critical_or_high_count**: count of accounts with risk_level `critical` or `high` among ALL reviewed accounts198- **arr_at_risk**: sum of `current_arr` for all reviewed accounts whose risk_level is NOT `low` (i.e., critical + high + medium)199- **collections_count**: count of accounts (in the returned top N) with `primary_action: "collections_followup"`200- **technical_recovery_count**: count of accounts (in the returned top N) with `primary_action: "technical_recovery"`201- **net_revenue_exposure** (when present): `arr_at_risk - open_expansion_pipeline`202- **linked_followup_count**: count of overdue_followups with `link_status: "linked"`203- **unlinked_followup_count**: count of overdue_followups with `link_status: "unlinked"`204- **strategic_accounts**: count of reviewed accounts with `segment: "Strategic"`205- **enterprise_accounts**: count of reviewed accounts with `segment: "Enterprise"`206- **open_expansion_pipeline**: sum of all `expansion_pipeline` values across reviewed accounts207208### Pipeline Summary209210- **won_count / won_revenue**: opportunities with `state: "closed"` AND `stage` ending in "Won"211- **lost_count**: opportunities with `state: "closed"` AND `stage` ending in "Lost"212- **open_count / open_pipeline**: opportunities with `state: "open"`213- **win_rate_pct**: `won_count / (won_count + lost_count) × 100`, to 1 decimal214- **top_open_product_line**: the `product_line` with the highest total `amount` among open opportunities215216### QBR Highlights217218- **average_revenue**: mean of the 3 monthly revenue values, 2 decimals219- **peak_revenue_month**: month with highest revenue220- **max_sla_month / max_sla_pct**: month with highest SLA %; on ties, pick the earliest month chronologically221- **peak_nps_month / peak_nps_score**: month with highest NPS score222- **ticket_trend**: compare total clean tickets across months — decreasing → `improving`, increasing → `worsening`, stable → `flat`223224### Churn Model Validation225226- **feature_count**: count the feature columns in the training CSV (exclude `customer_id` and the target column `Churn`)227- **training_rows / validation_rows**: row counts from the respective CSV files (excluding header)228- **accuracy_pct**: from the model evaluation, 1 decimal229- **accuracy_band**: map accuracy_pct to the correct band230- **tenure_coefficient_direction**: `negative` if lower tenure → higher churn probability, `positive` if higher tenure → higher churn, `zero` if no relationship231- **average_probability_top5**: mean of the top 5 predicted churn probabilities, 3 decimals232- **past_due_shortlist_count**: among top 5, count where `InvoicePastDue` = `"Yes"` in candidates.csv233- **low_tenure_shortlist_count**: among top 5, count where `tenure` ≤ 24 in candidates.csv234235### Policy Codes236237All tasks with `policy_codes` use the template's pipe-separated options. Select the **middle value** from each `CODE-LOW|CODE-MID|CODE-HIGH` triplet by default. The specific selection may vary based on data characteristics (e.g., which risk model version applies, which revenue source is used). Always select exactly one value per code key — never leave the pipe-separated template string.238239---240241## Sorting Conventions242243- **Risk accounts**: descending by `risk_score`244- **Overdue followups**: ascending by `customer_name` (lexicographic, case-sensitive)245- **QBR metrics**: ascending by `month` (chronological)246- **Action board**: all reviewed accounts, descending by risk (highest risk first)247248---249250## JSON Output Rules2512521. **Valid JSON only** — no markdown fences, no trailing commas, no comments2532. **null vs 0**: Use `null` for inapplicable/missing values (e.g., `next_touch_due_date` for `no_action`, `account_id` for unlinked A/R customers). Use `0`/`0.0` for true zero values2543. **Empty strings**: Not used in answers; use `null` or omit instead (template placeholders like `""` get filled with real values or `null`)2554. **All keys from the answer template must be present** in the output, even if some are `null` or `0`2565. **Controlled enum values only** — never invent new labels257258---259260## Workflow Pattern261262For any task using this API:2632641. **Read the answer template** (`input/payloads/answer_template.json`) to understand the exact output shape and enum options2652. **Identify the required endpoints** from the task prompt's endpoint families or data-source descriptions2663. **Fetch all data in parallel where possible** — account profiles, metrics, tickets, NPS, A/R, opportunities can all be fetched concurrently since they're independent2674. **Apply cleaning rules** to tickets (exclude spam/duplicate/cancelled)2685. **Compute derived values** (risk scores, SLA %, summaries, trends)2696. **Assemble the JSON** following the template shape, precision rules, and enum vocabularies2707. **Validate**: ensure all template keys are present, all enums are valid, precision matches rules, counts are consistent2718. **Return JSON only** — no explanatory text272273---274275## Common Pitfalls276277- **Using wrong ARR source**: For risk/retention tasks, `current_arr` comes from billing data, not CRM. Check `uses_billing_arr_source` and `arr_source_code` in the template.278- **Including spam/duplicate/cancelled tickets in clean counts**: Always filter to clean tickets before counting or computing SLA.279- **Using resolution_sla_met instead of first_response_sla_met**: SLA compliance for QBR and risk assessment is based on first-response SLA, not resolution SLA.280- **Including 1_30 and 31_60 buckets in overdue_balance**: Only `61_90` + `90_plus` count as overdue.281- **Fuzzy A/R matching**: Account linking must be exact string match against `legal_name` and each `account_aliases` entry. "Globex North Subsidiary LLC" ≠ "Globex North Subsidiary".282- **Counting closed opportunities as pipeline**: Only `state: "open"` opportunities count toward `expansion_pipeline`.283- **Wrong precision**: Churn probabilities need 3 decimals, not 2. Currency needs exactly 2 decimals. Risk scores are integers.284- **Inventing enum values**: Use only the exact enum strings from the answer template.285- **Not returning all accounts in action boards**: When the task says "return all accounts," include every reviewed account, not just top N.286- **Using localhost URLs**: Always use the remote URL from `environment_access.md`.