Header matching
Which column headers in a broker's file map to each Plansight field. Matching is case-insensitive and ignores _ - . and extra spaces. Add more spellings on the “Add a rule” tab.
Value conversions
How messy cell values become canonical values. Every rule carries provenance — the carrier/file that taught it.
Household rule — same_household → Ideon
Ideon requires a same-household flag on every dependent. We set it per relationship — not from the broker's yes/no — so a spouse/partner is never accidentally dropped from the quote.
Add a rule
Compose a new header spelling or value conversion here — no code. It builds the exact rule and lets you download the updated rules file to hand to a developer (or drop into the repo). Live in-app editing is the next step once the rules store lands.
Ideon business rules — what they are & how Roster uses them
The small-group enrollment rules Ideon applies at quote time, extracted from the carrier business_rule_sets feed (2026 Q3, all 51 states). This is the census-side view of the master catalog aca-data-project/BUSINESS-RULES-AND-SELF-QUOTING.md. Enforce = Roster acts at import · Flag = warns, never blocks · Info = shown for reference · Rate = matters only when premiums are built (passed through untouched).
Per-state envelope
The extremes across every carrier/plan in a state — what Roster can assert before a specific carrier is chosen. Rules resolve per plan at quote time; a dependent over the age cap can't enroll in any plan, which is why Roster ages them off at import.
Statutory disability & paid family leave
States where employers have statutory obligations — mandated disability insurance and/or paid family & medical leave. Census members living in these states are flagged in the importer's residency panel (and carried in the payload), because obligations follow where members live — and Plansight carries the matching plan types (nyDisability, spfl).
Carrier composite factors
For small-group community-rated quoting: which carriers in a state can bill on composite (one blended rate per tier) vs list-billed (per member) only. A carrier that publishes composite factors can do composite; if it has none, it's list-billed only. Factors are the 4-tier multipliers relative to Employee only = 1.0. Source: the Ideon issuer feed (latest quarter per state).
Connect Roster to V1
Roster is a modal overlay, like Flatfile/Scout: one script tag, one call, one callback. Roster hosts no data — the widget parses in the browser and hands the clean payload back.
1. Mint a short-lived JWT (server-side)
use Firebase\JWT\JWT;
JWT::encode([
'iss' => 'plansight-v1', 'aud' => 'plansight-roster',
'exp' => time() + 300, // 5 min
'context' => ['rfpId' => $rfpId, 'groupId' => $groupId],
], env('ROSTER_SIGNING_KEY'), 'HS256');
HS256, shared secret, ~5-min TTL, audience plansight-roster, issuer plansight-v1. Never ship the key to the browser.
2. Drop in the launcher
<script src="https://plansight-roster-stage.vercel.app/embed.js"></script>
<script>
PlansightRoster.open({
token: "{{ mintRosterJwt() }}",
schema: "aca-medical-census", // or "disability-census" / "carrier-rep-import"
state: "{{ $group->state }}", // census: employer state (drives age-out rules)
effectiveDate: "{{ $rfp->effective_date }}", // census: YYYY-MM-DD
planOptions: {{ $group->plan_options }}, // census: available medical plan options
offices: {{ $brokerage->office_names }}, // carrier-rep: the brokerage's offices
onSuccess: (payload) => { // census: payload.employees (EN shape)
// carrier-rep: payload.records (RfpDistributionListDefaults shape)
},
onCancel: () => {},
});
</script>
3. Endpoints
4. The payload & Ideon mapping
Roster returns the Employee Navigator Quote Census v1 shape — the same shape V1's EN sync already consumes. V1 derives the Ideon /quotes request from it.
| Ideon field | From our payload |
|---|---|
| external_id | plansightMeta.eeId |
| date_of_birth | demographics.birthDate (YYYY-MM-DD) |
| gender | demographics.sex → M / F (Unspecified must be resolved) |
| zip_code | demographics.addresses.homeAddress.postalCode |
| fips_code / location_id | V1 computes from ZIP/state |
| cobra / retiree | plansightMeta.cobra / .retiree |
| last_used_tobacco | demographics.tobaccoUseInformation.lastUsedDate |
| dependents[].relationship | Spouse→spouse, Child→child, LegalDependent→ward |
| dependents[].same_household | Per relationship (see Household rule): Spouse/partner → true, all others → false |
5. Error events (via the callback)
token_expired — mint a fresh JWT · schema_unknown — bad schema id · network_failed — Roster API unreachable.
Preview the embed theme
Roster restyles itself to match the app it's embedded in — it's all CSS design tokens (color, corners, font), so no host CSS is touched. Pick a host style or nudge the knobs; the live preview below is the real importer in that theme. The host applies whatever you land on via PlansightRoster.open({ theme: … }) — copy the snippet.
The preview below is live and clickable — or hit Open full importer to demo to launch it full-screen in its own tab (upload a census, click through, print) with these exact theme settings. That URL is also shareable for a demo: