Skip to content

Reports & analytics

Reports read pre-computed period rollups, so they’re fast enough for dashboards and trend charts. All amounts and counts come from the same scored dataset as the grid and the comparison API.

Rollup — green / yellow / red for a period

Terminal window
curl "https://api.commissionsight.com/v1/reports/rollup?period=2026-04&carrierId=$CARRIER_ID" \
-H "Authorization: Bearer $TOKEN"

period defaults to the latest period with data; carrierId is optional.

{
"period": "2026-04",
"totals": {
"memberCount": 9672, "green": 8120, "yellow": 940, "red": 612, "new": 210, "reappeared": 34,
"commissionAtRisk": 48230.55, // dollars on yellow + red members this period
"commissionDropped": 31010.00, // the red (dropped) slice of at-risk
"commissionReduced": 17220.55, // the yellow (reduced) slice of at-risk
"reducedCount": 410, // members whose commission went down
"commissionOwed": 12640.40, // recoverable shortfall (expected − actual)
"owedEvaluated": 8900, // members the owed engine could evaluate
"owedTotal": 9100, // members owed was attempted on
"owedEstimated": false, // true if owed is built on an auto-seeded estimate rate
"chargebackCount": 18, "chargebackAmount": 2240.00
},
"byCarrier": [ { "carrierId": "", "memberCount": 1260, "green": 1190, "yellow": 55, "red": 15, "new": 8, "reappeared": 2, "attritionRate": 0.011, "commissionAtRisk": 5120.00, "commissionOwed": 1840.00, "chargebackAmount": 0 } ]
}

Each byCarrier entry carries the same per-carrier fields as totals (plus attritionRate). owedEvaluated ÷ owedTotal is the owed-coverage ratio — how much of the book the recoverable figure is based on. owedEstimated is true when the owed figure is (partly) built on an auto-seeded estimate rate rather than a rate you’ve confirmed — treat the dollars as approximate until you set your contracted rate (it flips to false once you do). See Commission owed.

Attrition — point in time

Terminal window
curl "https://api.commissionsight.com/v1/reports/attrition?period=2026-04" \
-H "Authorization: Bearer $TOKEN"

period is required. Attrition ≈ red ÷ members present in the prior period, returned overall and per carrier. (The projection approximates the prior-period denominator as present + dropped; for exact member-level movement use /comparisons.)

Attrition — trend series

Terminal window
curl "https://api.commissionsight.com/v1/reports/attrition-series?months=12&carrierId=$CARRIER_ID" \
-H "Authorization: Bearer $TOKEN"

Month-over-month attrition for the last N periods (1–36, default 12), oldest → newest — ready to plot. Each point: { period, year, month, red, memberCount, attritionRate, commissionAtRisk }commissionAtRisk is the dollars on yellow + red members that period, so you can plot lost-revenue alongside the rate.

Cumulative — audit totals over a range

Terminal window
curl "https://api.commissionsight.com/v1/reports/cumulative?from=2025-01&to=2025-12&carrierId=$CARRIER_ID" \
-H "Authorization: Bearer $TOKEN"

The audit roll-up: commission owed, at-risk, and chargebacks summed across a period range, with month-by-month and per-carrier breakdowns. from/to (YYYY-MM) are inclusive and both optional — omit them for the entire book. Scope with carrierId / workspaceId.

{
"range": { "from": "2025-01", "to": "2025-12", "requestedFrom": "2025-01", "requestedTo": "2025-12", "periodsCovered": 12 },
"totals": {
"commissionOwed": 4204.10, // Σ expected-vs-actual shortfall over the range (recoverable)
"commissionAtRisk": 12880.00,
"chargebackAmount": 3540.00, "chargebackCount": 24,
"owedEvaluated": 7600, "owedTotal": 13800,
"owedCoverage": 0.55, // cumulative Σ evaluated ÷ Σ total
"memberMonths": 13800, // Σ per-period member counts — a VOLUME, not distinct members
"avgMembers": 1150, "peakMembers": 1260,
"red": 540, "new": 410, "reappeared": 120,
"owedEstimated": false
},
"byPeriod": [ { "period": "2025-12", "memberCount": 1260, "commissionOwed": 268.22, "commissionAtRisk": 167.12, "chargebackAmount": 0, "owedEvaluated": 1180, "owedTotal": 1260, "owedCoverage": 0.94, "red": 6, "new": 12, "reappeared": 4 } ],
"byCarrier": [ { "carrierId": "", "carrierName": "Aetna Senior Supplemental", "commissionOwed": 4204.10, "commissionAtRisk": 12880.00, "chargebackAmount": 3540.00, "owedEvaluated": 7600, "owedTotal": 13800, "owedCoverage": 0.55, "memberMonths": 13800, "periodsCovered": 12 } ]
}

memberMonths is a volume, not a head-count. It’s the sum of each period’s member count, so a 12-month range over a ~1,150-member book is ~13,800 — use avgMembers / peakMembers for the size of the book. commissionOwed is correctly cumulative: each period’s owed is that period’s expected-minus-actual, so summing them is the total recoverable over the window.


Statement-quality (data-quality) signal

Terminal window
curl "https://api.commissionsight.com/v1/reports/data-quality?period=2026-04" \
-H "Authorization: Bearer $TOKEN"

A per-carrier, per-period grade — ok · watch · alert — of whether the statement you uploaded looks complete and from the right period. It’s a guard that runs before you trust a carrier’s fallout and attrition numbers: an incomplete or wrong-period file makes a slice of the book look like it churned when it didn’t, and this flags it so you don’t act on bad data.

Each carrier returns a level, a plain-English reason, and the underlying rates. When a carrier is alert, treat the statement as suspect — re-pull the correct, complete file and re-upload (and re-process the affected period); the numbers then reflect reality.

Medicare rapid-disenrollment (RDE) radar

Terminal window
curl "https://api.commissionsight.com/v1/reports/medicare-rde?carrierId=$CARRIER_ID&period=2026-06" \
-H "Authorization: Bearer $TOKEN"

CMS advances Medicare commission and claws back the full amount if a member disenrolls inside the first ~3 months (a rapid disenrollment). For one carrier and period this returns a radar with:

  • realized{ count, clawedBackAmount }: rapid disenrollments whose commission was clawed back this period (the money already gone).
  • exposure{ count, atRiskAmount }: active members still inside the RDE window — if they leave now, the full advance claws back. The “see it coming” figure.
  • disenrollments{ total, rapid, rapidRatePct }: of everyone who left, the share that was rapid.
  • byPlan / byAgent — where the rapid disenrollments concentrate (which products and producers churn early), each with the dollars clawed back.

carrierId is required; period defaults to the carrier’s latest. Classification needs an effective date and a disenrollment/term date on the statement — records missing either are counted in total but never guessed, and evaluated ÷ total reports the coverage.

Medicare renewal & book-value forecast

Terminal window
curl "https://api.commissionsight.com/v1/reports/medicare-renewal-forecast?carrierId=$CARRIER_ID" \
-H "Authorization: Bearer $TOKEN"

Projects the next horizonMonths (default 12, max 24) of renewal commission across the active book. Each active member renews once a year on their enrollment anniversary at the CMS renewal rate (your configured schedule, else the bundled CMS maximums — ratesInferred: true). Over a 12-month window that’s the book’s annual recurring renewal income — the figure agencies value a book on. Returns a forecast with annualRenewalValue, activeMembers, evaluated (members we could price), byMonth (anniversary seasonality), and byPlan. It assumes retention — pair it with the RDE radar above for the downside. carrierId required; period (the “as-of” book) defaults to the latest.

Unpaid members (census reconciliation)

Terminal window
curl -X POST "https://api.commissionsight.com/v1/reports/census-reconcile" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{ "carrierId": "car_123", "members": [ { "memberExternalId": "M-1001" }, { "memberExternalId": "M-1002" } ] }'

The biggest find-money check: members you know are active that the carrier never paid you for. POST your active-member roster (members[].memberExternalId, optional name/planName) and we compare it to who the carrier actually paid on the statement. Returns a result with unpaid (roster members with no paid record — the recoverable list), estimatedUnpaidAmount (unpaid count × the matched members’ median paid commission — a basis grounded in your own statement), matched / censusTotal coverage, and unrostered (paid members missing from your roster — a stale roster, or members you forgot). Nothing is stored — the roster is reconciled in memory and discarded. carrierId required; period defaults to the latest. Matching is by member id (case/space-insensitive).

Carrier scorecards

Terminal window
curl "https://api.commissionsight.com/v1/reports/carrier-scorecards?from=2025-01&to=2025-12" \
-H "Authorization: Bearer $TOKEN"

Ranks your carriers worst grade first — who to lean on, who to chase. The grade scores carrier behavior: reliability (a statement every active month, 60%) + cleanliness (statements that don’t look incomplete/wrong-period, 40%). The money metrics are reported alongside (not baked into the grade with arbitrary thresholds): commissionOwed, owedPerMemberMonth, chargebackAmount, dropRatePct, plus consistencyPct, periodsReported/periodsExpected, qualityFlags, and avgMembers. from/to (both optional) bound the window; with neither, it uses every active month. Reads the fast projection — no data-plane hit.

Year-end 1099 reconciliation

Terminal window
curl "https://api.commissionsight.com/v1/reports/tax-1099?year=2025" \
-H "Authorization: Bearer $TOKEN"

Tallies the commission each carrier actually paid over a tax (calendar) yearpaidNet (net of chargebacks), paidGross, chargebacks, and periodsCovered per carrier — so you can check it against the carrier’s 1099 box amount. A mismatch is mis-reported income worth a conversation with the carrier (and your accountant). year is required; the tally reflects the statements you’ve loaded, so load every month for an apples-to-apples check.

Saved & scheduled reports

Any plain-English question you ask the assistant generates a read-only query; you can save that query as a named report and re-run it any time, or have it emailed on a schedule. These are app-only endpoints (not part of the SDK).

Method & pathWhat it does
POST /v1/reports/savedSave a report. Body: { name, question?, sql }. The sql must pass the same read-only guard the assistant uses (a single SELECT/WITH, bounded) — anything else is rejected 422.
GET /v1/reports/savedList your saved reports (name, question, cadence, last run).
POST /v1/reports/saved/:id/runRe-run the stored query against your data → { columns, rows, truncated }. Deterministic — no AI.
PUT /v1/reports/saved/:idSet the email digest cadence. Body: { cadence: "off" | "weekly" | "monthly" }.
DELETE /v1/reports/saved/:idDelete a saved report.

When a report has a weekly/monthly cadence, a scheduled job runs it and emails the results to your account on that interval. In the app, save and schedule reports right from the Ask AI screen.