GET /groups/{groupId}/account: funding, premium-equivalent totals, spend, and savings.GET /groups/{groupId}/members: the enrollment roster of who’s invited, active, and on COBRA.
Aggregate and de-identified by design. The account payload never contains named claims, diagnoses, or any individual’s health data, and spend categories are suppressed (k-anonymity) when a category could be traced to a small number of members. You can’t accidentally render PHI, because the API never returns it. See Compliance.
404 not_found until the group is enrolled. Pre-enrollment, use GET /census for roster display.
The account payload, in force
Acme Inc, two months after their 2026-09-01 start, activated toprod:
funding.monthlyFundingCents equals premiums.monthlyPremiumEquivalentCents, the breakdown sums to it exactly, and savings.savingsYtdCents is derived from the active baseline comparison.
Field-by-field UI mapping
| UI element | Field(s) | Display guidance |
|---|---|---|
| Tab header / plan badge | plan.name, company.state | ”Prescience Diamond”. Show an “Onboarding” badge while state is sandbox. |
| Plan dates | company.startDate, company.renewalDate | ”Plan year Sep 1, 2026 – Sep 1, 2027”. |
| Covered population | population.* | ”19 covered lives: 12 employees + 7 dependents”. |
| Funding balance | funding.fundBalanceCents | Headline number: “$9,901.44 in plan fund”. Sub-label months-on-hand: balance ÷ monthlyFundingCents → “≈1.5 months”. |
| Upcoming pulls | funding.upcomingPulls[] | ”Next pull: $6,600.96 on Dec 1” with status chip (scheduled / completed). recentPulls is the history table. |
| Monthly cost | premiums.monthlyPremiumEquivalentCents, pepmCents | ”$6,600.96/month · $550.08 per employee”. |
| Employee premium contribution | premiums.employeeContributionCents | Integer cents. |
| Premium breakdown | premiums.breakdown[] | Label/value rows or a chart. Preserve zero-value rows if your UI shows the full breakdown. |
| Spend summary | spend.mtdCents, spend.ytdCents | ”Claims spend: $234.18 this month · $8,023.40 plan-year-to-date”. |
| Spend by category | spend.categories[] | Bar list with pct. Sorted by size already. |
| Suppressed state | spend.suppressed, spend.suppressionNote | See below; this state must be designed, not ignored. |
| Savings | savings.* | baselineAnnualCents is prior-plan cost projected over the plan year; savingsYtdCents is current plan-year savings against that baseline. |
The suppressed-spend case
For small groups (or early plan years), category-level spend could let an employer guess at an individual’s care. When the k-anonymity check trips, the API withholds categories rather than thin them:suppressionNote, and treat it as a normal state, not an error or an empty-data bug. Categories reappear automatically once the population supports them.
The roster
GET /groups/{groupId}/members powers the people table, with enrollment-admin data only:
| Column | Field | Notes |
|---|---|---|
| Name / email | firstName, lastName, email | Join to your employee record via externalId. |
| Status | status | active / terminated / cobra; show COBRA with cobra.until (“COBRA through May 31, 2028”). |
| Dependents | dependents | A count, deliberately; no dependent details post-enrollment. |
| App status | enrollment.invited, enrollment.accountCreated | The useful HR nudge: invited-but-no-account members are who to ping during open enrollment. |
dependents is a count and enrollment is two booleans on purpose: the roster tells the employer who is covered and onboarded, never anything about anyone’s health.
Freshness
asOf timestamps every account read. The data behind it updates as pulls settle and claims process. Cache for minutes, not days; on-load fetching with a short server-side cache is the pattern our own portal uses. Both endpoints fall under the standard 120 req/min rate limit.