+

Two-way sync between quoting and the book of business

The bidirectional integration between Plansight's quoting platform and Vertafore's BenefitPoint agency management system — keeping every plan, rate, benefit summary, and renewal in sync between the system brokers quote in and the system of record they bill from.

Browse the interactive Sync Map
Plansight · Built 2021 · Continuous · Confidential · Vertafore BP REST API docs ↗
Overview

What is the BenefitPoint integration?

A purpose-built, two-way data bridge between Plansight and BenefitPoint. Brokers quote and shop plans in Plansight, then push them to BenefitPoint with one click — and BenefitPoint's authoritative book of business flows back into Plansight so brokers always work from a single source of truth.

42
API Operations
17+
Brokerages Synced
24
Plan Types Supported
2-Way
Sync & Push

Pull from BenefitPoint

Brokers associate a Plansight account with a BenefitPoint account. Every product, plan, rate, benefit summary, and contribution rule on the BP side is imported and kept current — automatically — through scheduled change-tracking calls.

Push to BenefitPoint

When a broker finishes shopping and the client picks a plan, Plansight builds the BenefitPoint product, benefit summary, rate structure, contributions, and eligibility — and pushes it directly into the BP record. No re-keying, no double entry.

Renewal-aware

Every plan tracks an origination reason — new, renewal, or replacement — and the integration applies the right copy-from-prior, send-fresh, or auto-match logic per reason. Renewal pushes auto-match the BP plan; new pushes prompt for taxonomy.

Multi-tenant by design

Every brokerage configures its own BenefitPoint API credentials and runs in isolation — separate Web Services authentication, separate per-brokerage cache, separate feature flags. The same code path serves single-office shops and 50-office multi-region brokerages alike.

Why

Why this integration exists

Brokerages live in BenefitPoint. It's where they manage commissions, books of business, renewals, and the agency operations that keep the lights on. Plansight is where the work of quoting happens. Without integration, those two worlds require duplicate data entry on every plan that gets sold.

For the broker

Quote in the platform built for it. Push the result into the system of record with one click. No spreadsheet hand-offs, no dual entry, no "I forgot to update BP." When BP is the source of truth on renewals, Plansight stays in lockstep — automatically.

For the agency

Compliance, commissions, and reporting all run off BenefitPoint. The integration means every plan Plansight produces is BP-correct: right product type, right carriers, right rate structure, right benefit summary, right effective dates. Audit-ready by default.

For the client

The plan that wins on screen in Plansight is the same plan that gets billed, renewed, and serviced. No translation errors. No "we're showing one rate but BP has another."

For Vertafore

Plansight is BenefitPoint's preferred quoting partner. The integration makes Plansight a natural extension of BP — the front-end where the modern broker workflow lives, feeding the agency-management spine BP already provides.

The shape of the value

Quoting, presentation, and shopping are upstream activities — they're best done in a tool purpose-built for them (Plansight). Servicing, billing, commissions, reporting, and historical tracking are downstream activities — they belong in the system that's done them for decades (BenefitPoint). The integration is the seam: it makes the upstream and downstream behave like one system.

How it works · Push

Plansight → BenefitPoint

When a broker hits "Push to BenefitPoint" in Plansight, here's what happens.

1

Validate the plan group

The job loads every quote in the plan group from a fresh database read, verifies they all belong to the same plan group, and clears any prior error state. Single-mode pushes one quote; multi-summary mode pushes every quote as its own benefit summary.

2

Pull live account context

Before building anything, the integration calls GetAccount to fetch the current primarySalesLeadUserID and primaryServiceLeadUserID directly from BP. These were historically cached on the Plansight quote, but recent changes always re-fetch them so renewals never carry stale lead assignments.

3

Build the BenefitPoint payload

ProductModel::fromPlansightModels($quotes) assembles the BP product object: name, plan type, carriers (writing + billing), origination reason, effective and renewal dates, policy/group number, and every benefit attribute mapped through Plansight's BP-code dictionary.

4

Push via REST (or SOAP)

By default, products push via the modern REST endpoint — CreateProductRest with a JSON body. Brokerages on custom WSDL URLs push via SOAP CreateProduct. The product is created with view level Core (110); admin overrides are available to "overwrite" an existing product.

5

Chain in benefit summaries, rates, contributions, eligibility

After the product is created, postProcess() runs the dependent operations: UpdateBenefitSummary (or CreateBenefitSummaryFromCopy on renewal), CreateRateRest per rate type, CreateContributionRest per contribution structure, CreateEligibilityRuleRest, and a DeleteBenefitSummaryRest to clean up BP's auto-created "All Employees" empty summary if the broker wants to replace it.

6

Surface errors with context

If any step fails, the JSON error response is parsed and decorated. "Invalid billingCarrierID for the selected billingCarrierType" becomes "Billing carrier 'Aetna' is not valid for product type 'Medical PPO'" — with the carrier name, billing carrier type, and product type all resolved from the per-brokerage cache. The error is stored on the quote so the UI can show it next to the right plan.

Why a Job and not a synchronous request?

The push runs as an async queue job. Pushing a multi-option plan group with renewal carry-over from prior plans can fan out to 20+ BP API calls — and BP's API can take a few seconds per call. Running on the queue means the broker's UI returns instantly, the user sees a "pushing..." status, and any retries happen without breaking the user's flow.

Per-brokerage feature flags

Two push-side capabilities are toggled per-brokerage rather than universally. Both are off by default; turn-on is a deliberate decision per brokerage.

Both flags live on the brokerage record. Coordinate with whoever owns brokerage configuration before flipping either one — they meaningfully change what BP sees on the other side.

How it works · Pull

BenefitPoint → Plansight

Plansight stays current with the BenefitPoint book of business through three nested jobs running on a low-priority queue.

1

Brokerage-level fan out

PullProducts(brokerageId) finds every Plansight group with a benefitPointId and dispatches PullProductsByGroupId for each — typically hundreds of jobs for a large brokerage.

2

Group-level product list

FindProducts(benefitPointId) lists every product on the BP account. The integration deduplicates BP's known internal product-replication bug, applies the reachBackRenewalDate filter to skip ancient plans, and dispatches PullProductById for each survivor.

3

Single-product import

Service::importProduct(groupId, productId) calls GetProductRest, FindBenefitSummaries, FindRates, GetContributionsSummaryList, GetEligibilityRuleSummaryList — and assembles a complete Plansight quote from the responses.

4

Map BP IDs to Plansight fields

Every numeric BP attribute ID (45 = Per Individual deductible, 386 = Primary Care, 414 = Specialist, 902 = Telehealth, etc.) is translated to its Plansight equivalent through the master attribute map. Unsupported plan types are filtered against the deny-list.

5

Save as a Plansight quote

A QuoteBenefitHistory is created or updated with source = 'benefitPoint', BP's product ID written back via setIntegrationData, and the right origination reason inferred from the BP product's history.

Recurring delta sync

The full pull is heavy. For day-to-day freshness, the benefit-point:pull-changes artisan command runs on a schedule, calling BP's FindChanges API to pull only what's changed since last run — minutes of work instead of hours.

What we sync

The 24 plan types Plansight supports

BenefitPoint's product taxonomy has hundreds of entries — annuities, executive benefits, individual lines, retirement products, and more. Plansight integrates the 24 plan types brokers actually quote in modern employee benefits.

Medical

Synced Medical HMO, PPO, POS, EPO, Indemnity

Synced Prescription Drug Carve-Out

Synced Stop Loss

Synced Telehealth, Patient Advocacy

Synced Transplant Carve-Out

ToDo Medical Gap (GAP)

Administration

Synced HRA

Synced HSA

Synced FSA

Synced COBRA Administration

ToDo FMLA / Leave Management

Ancillary

Synced Dental — Managed, PPO, HMO, Triple Option, Indemnity

Synced Vision & Voluntary Vision

Synced Basic Life and AD&D

Synced Voluntary Life and AD&D

Synced Short Term Disability (STD & Voluntary)

Synced Long Term Disability (LTD & Voluntary)

Synced Employee Assistance Program (EAP)

Synced Legal, Pet Insurance, Identity Theft

Worksite / Voluntary

Synced Accident & Voluntary Accident

Synced Hospital Indemnity

Synced Critical Illness & Voluntary Critical Illness

Synced Cancer Coverage & Voluntary Cancer

Intentionally not synced

Skip Group Term Life, AD&D-only, BTA

Skip 401(k), 403(b), 457, 529, IRA

Skip Annuities, Universal Life, Whole Life

Skip Individual Medical / Dental / Vision

Skip Executive Benefits (FCC) lines

Skip International Bundled, State Statutory DBL/TDB/TDI/SDI

Plan vs Product

BenefitPoint divides offerings into Plans (carry rate and benefit data — Medical, Dental, etc.) and Products (services without rate structures — Telehealth, COBRA, etc.). Plansight syncs Plan Information for both, but only pulls Plan Design + Rates for actual Plans.

Open the full filterable Sync Map

Every plan type, product type, and benefit attribute · filterable by sync status

The Field Map

How attribute codes get translated

BenefitPoint identifies every benefit attribute by an internal numeric ID. Plansight maintains a master mapping that translates those numeric codes into Plansight's named fields, in both directions.

Plansight Field BP ID Notes
Per Individual Deductible45Annual medical deductible, in-network individual
Per Family Deductible44Annual medical deductible, in-network family
Deductible Type973Embedded vs aggregate
HSA Eligible873High-deductible health plan flag
OOP Per Individual53Annual out-of-pocket maximum, individual
OOP Per Family52Annual out-of-pocket maximum, family
Primary Care386Office visit copay/coinsurance
Specialist414Outpatient specialist visit
Telehealth902Telemedicine
Emergency Room184ER copay/coinsurance
Urgent Care555Urgent care facility
Inpatient295Inpatient facility & physician
Mental Health Outpatient407Mental health outpatient services
Substance Use Inpatient670Substance use inpatient hospitalization
Rx Tier 1 (Generic)880Preferred generic drug tier
Rx Tier 484Non-preferred brand
Mail Order378Mail-order Rx

Why these codes matter

BenefitPoint doesn't expose its attribute codes in normal API responses — they're internal IDs. Plansight extracted them via metadata calls (GetBenefitSummaryStructure, GetProductTypes, FindRates) when the integration was first built and maintains them as the source of truth for every push and pull. The full dictionary covers Medical, Pharmacy, Stop Loss, Dental, Vision, EAP, Basic Life, Voluntary Life, HRA, STD, and LTD.

Connected Systems

What the integration talks to

Both sides of the pipe — what comes in from BenefitPoint, and where the resulting data lives in Plansight.

BrokerConnect REST API (Vertafore)

The modern REST endpoint for product creation, rate creation, contributions, eligibility rules, and benefit summary management. The default API surface for new pushes since 2024.

Live

BrokerConnect SOAP API (Vertafore)

The legacy SOAP API on V4.2 / V4.3. Still used for accounts, listings, structure fetches, and any brokerage configured with custom WSDL URLs. Auth via session token cached for 55 minutes.

Legacy

Plansight DynamoDB

Where every imported account, plan, rate, contribution, and eligibility rule lands. The same store that powers Plansight's quoting flow — meaning BP-pulled data is immediately available to brokers without a translation layer.

Live

Plansight per-brokerage cache

Each brokerage has a dedicated cache holding BP offices, users, writing carriers, and billing carriers. Refreshed by the benefit-point:brokerage-cache command. Powers every dropdown that asks the broker to pick a BP entity.

Live

Redis queue (low-priority)

Bulk pulls and brokerage-wide syncs run on the redis-low queue. Push jobs run on the standard queue with retries and error context capture. Nothing blocks the broker's UI.

Live

Scheduled change-tracking

The benefit-point:pull-changes command runs on a recurring schedule, calling BP's FindChanges API to keep Plansight current without re-fetching the full book of business.

Live
Who it's for

The brokerages this serves

The integration is designed to work for any brokerage that runs its book of business on BenefitPoint and quotes new and renewal plans through Plansight. The shape of the work is the same regardless of size.

Single-office brokerages

One BP API user, one office, one set of carriers. Onboard once, push and pull from there. The integration's simplest case — and where most of the value comes through with the least configuration overhead.

Multi-office, multi-region brokerages

One BP API user can have access to multiple regions and offices. The integration scopes every operation to the offices the API user can see, so a national brokerage can run dozens of regional offices through a single Plansight tenant without cross-contamination.

Multi-entity groups

Brokerages that operate as multiple legal entities (acquisitions, subsidiaries, partner-brand structures) typically maintain separate BP carrier rosters. Each entity gets its own brokerage configuration — separate credentials, separate cache, separate feature flags — and shares only what should be shared.

High-volume agencies

Brokerages with hundreds or thousands of employer accounts move large amounts of data on a renewal cycle. The async queue architecture and scheduled FindChanges sync are designed for that scale — bulk pulls run on a low-priority queue, daily delta syncs keep things fresh without re-fetching the full book.

One code path, every brokerage

The same operations, the same struct definitions, the same BP code dictionary, the same job runners serve every brokerage running on the integration. Tenant-specific behavior is expressed through per-brokerage feature flags and credentials — never through forks of the integration code itself. That's how it stays maintainable as more brokerages join.

Architecture

How it's built

A self-contained Laravel package inside the Plansight monolith, designed to be testable, debuggable, and operable per-brokerage without affecting other tenants.

Tech Stack

PHP

Backend: Laravel · PHP 8 · ~300 files

API: Native PHP SoapClient + Symfony NativeHttpClient for REST

Storage: AWS DynamoDB (per-brokerage tenant data)

Async: Redis queues — default for push, redis-low for bulk pulls

Cache: Per-brokerage flat-file BenefitPointCache + 55-min session token

Auth: Per-brokerage encrypted Web Services credentials

Package Structure

integrations/BenefitPoint/
├── Api.php          ← auth, SOAP/REST client, retry
├── Service.php      ← 3,309-line orchestrator
├── BenefitPointCache.php
├── Controller.php   ← all UI/HTTP endpoints
├── ContributionData.php
├── RateData.php     ← 188KB rate-mapping helper
├── Operations/      ← 42 API call wrappers
├── Structs/         ← 128 PHP DTOs (Account, Product,
│                       Rate, BenefitSummary, …)
├── Enums/           ← 112 BP value sets
├── Jobs/            ← 6 async queue jobs
├── Commands/        ← 6 artisan CLI commands
├── Concerns/        ← shared traits
├── Contracts/       ← Operation interface
├── Views/           ← Blade templates
└── Scripts/BP.js

Operability

Per-brokerage feature flags

Integration on/off, multi-summary mode, custom WSDL URLs — all per-brokerage. Can disable mid-incident without code change.

Structured error capture

Every push error stores parsed JSON, raw response, and resolved entity names on the quote — surfaceable in the UI without digging through logs.

Truncation-aware logging

SOAP request/response logged to bpDebug, with smart truncation for noisy operations like findOffices, createBenefitSummary, and getBenefitSummaryStructure.

Lifecycle

The renewal year, in motion

A typical client's plan lives in both systems for years. Here's how the integration handles each phase of the renewal cycle.

1. New plan

Broker shops a new plan in Plansight, picks a winner, clicks "Push to BenefitPoint". The integration picks the BP plan type from BP's taxonomy, builds the product with origination reason new, sends rates and benefit summary, and stores the BP product ID on the Plansight quote.

2. Steady state

The plan lives in BP. Plansight's scheduled pull-changes command keeps the broker's view in sync — if anyone updates the plan in BP (rate change, carrier change, contribution adjustment), Plansight reflects it within the next sync window.

3. Renewal cycle begins

120 days from renewal, Plansight surfaces the renewing plans. The broker shops the renewal in Plansight, comparing carriers and options. The integration knows the parent plan and pre-populates Plansight with the prior plan's structure.

4. Renewal push

When the renewal is ready, the broker pushes with origination reason renewal. The integration auto-matches to the existing BP plan, copies forward Broker of Record, Splits, Eligibility, and Contributions from the prior plan, and overwrites only what changed — rates, benefit attributes, dates.

5. Replacement

If the broker switches carriers entirely, origination reason becomes replacement. The new plan gets pushed fresh, but with the parent's identity preserved so BP's reporting connects the old policy and the new one as a single ongoing relationship.

6. Mid-year changes

Mid-year amendments (rate changes, carrier corrections, eligibility tweaks) flow through the same push pipeline. The broker edits in Plansight, pushes, and BP's record updates. No re-keying.

Origination reason is the master key

Every quote in Plansight carries an originationReason: new, renewal, or replacement. The integration's behavior — what's copied from the prior plan vs. sent fresh, what's auto-matched vs. user-picked, what error patterns are tolerated — branches off this single field. Get the origination reason right and the rest of the integration follows.

Design principles

How the integration reasons

Patterns that hold across every operation, every brokerage, every plan type.

One-to-one association

One Plansight account binds to exactly one BP account, and vice versa. No fan-out, no fan-in. This constraint keeps multi-office brokerages modeling their structure deliberately, and simplifies every downstream operation by removing ambiguity about which BP record a Plansight quote belongs to.

Control splits required

BP's control splits setting must be enabled on the BP side for the integration to function. Without it, associations succeed silently but pushes do nothing — a known failure mode that's now part of the pre-onboarding checklist.

Pull is safe; push is explicit

Sync from BP → Plansight runs on a schedule. Push from Plansight → BP is always user-triggered. The integration never silently writes to BP — every push corresponds to a deliberate broker action with a visible audit trail.

The deny list is explicit

Plansight maintains a 150+ entry list of BP product type IDs the integration intentionally skips: annuities, executive benefits, individual lines, retirement products. The list is checked in code on every operation. New plan types are added deliberately, never by accident.

Errors stay with the data

Every push error is captured on the quote it failed for, with a parsed JSON payload, a raw response, and resolved names for billing carrier, writing carrier, and product type. The broker doesn't need a log file to understand what went wrong.

Sessions are short, retries are graceful

BP session tokens cache for 55 minutes. When BP returns "session is not valid", the retry loop forgets the cache and re-logs in once, transparently. Brokers never see auth churn.

Single sign-on

SSO is built on our side, awaiting BenefitPoint rollout

Plansight has the receiving side of a BenefitPoint single-sign-on flow scaffolded and routed. The endpoint is live in production. BenefitPoint hasn't enabled the emitter on their side yet — once they do, the controller fleshes out the click-through experience.

What's deployed today

A pair of routes registered in routes/web.php:128-130 — both GET and POST on /benefitPointSSO. The controller (app/Http/Controllers/BPSSOController.php) is currently a placeholder that logs the inbound request payload via Log::debug and returns. Built by Trevor.

What's pending

BenefitPoint hasn't shipped the SSO emitter yet. When they do (Vertafore handles the timing), Plansight will see real signed payloads at /benefitPointSSO and the controller body needs to: validate the signature, resolve the BP user to a Plansight user, mint a Plansight session, and redirect to the right deep link (account, quote, etc.) inside Plansight.

Why this matters

SSO from BenefitPoint into Plansight removes the second login. A broker working in BenefitPoint can click a Plansight link and land on the right account/quote without re-authenticating. It's also the most natural point of integration to surface Plansight inside the BenefitPoint UI itself once Vertafore exposes the deep-link API.

Owner: Trevor on the Plansight side. Status: Waiting on Vertafore. When they have a date, the controller body is a half-day of work.

Gap analysis

What a deep code audit surfaced

Seven findings from a fresh pass through integrations/BenefitPoint/ in Plansight APP 9d1afd54d5df. None are existential — the integration works in production every day — but each is the kind of issue that produces "unreproducible" bug reports until someone goes looking. Rank order is rough impact-weighted.

1

FindChanges delta-sync is built but never invoked

Capability gap

Problem. Vertafore exposes FindChanges (returns only records modified since a timestamp) and Plansight has it implemented at integrations/BenefitPoint/Operations/FindChanges.php — but the only caller is Commands/PullChanges.php, which isn't wired into the main sync flow in Controller.php or Service.php. Every product sync today is a full refresh.

Why it matters. Full refreshes are slow and burn API budget. For brokerages with hundreds of accounts, this is the difference between a sync that takes seconds and one that takes minutes (or trips a rate limit, see #4 below).

Cursor prompt

Wire FindChanges into Service::syncBrokerageProducts(): check for a last_sync_at timestamp on the brokerage; if present, call FindChanges and use only the returned product IDs to drive detail fetches. Fall back to full sync when no timestamp exists or FindChanges errors. Update last_sync_at after a successful run.

2

Empty API responses overwrite cached data — silent corruption

Production-impacting

Problem. When FindOffices, GetAvailableCarriers, or FindUsers returns an empty collection (transient error, partial outage, auth slip), Service.php:2579-2590 still writes the empty result over the prior cache. The next UI request that depends on offices or carriers gets a silently empty list. Users see "no offices available" with no error surfaced.

Fix sketch. Reject empty replacements before persisting — keep the stale cached value and log a warning. An "empty after fetch" should be treated as "fetch failed" until proven otherwise.

Cursor prompt

In Service::putBrokerageUserCache(), before writing each of offices, users, availableCarriers, and billingCarriers to Storage::put, check if the new value is empty. If it is and a non-empty cached value exists, log a warning ("BP cache update rejected — empty {key} from API") and keep the prior value. Only overwrite when the new value is non-empty OR the prior value was also empty.

3

Login token cache keyed only by brokerage ID — multi-tenant collision risk

Multi-tenant correctness

Problem. Api.php:464-467 caches login tokens using just brokerage->id. The getLoginToken() method has a commented-out brokerageId parameter implying support for one Plansight brokerage bridging multiple BP tenants — but the cache key doesn't include it. If we ever turn that on (or a single brokerage's BP auth changes), tokens will collide across tenants.

Cursor prompt

Update loginCacheKey() in Api.php to include the Vertafore tenant ID when getBpData('brokerageId') is set: "benefitPointLoginCredentials_{$brokerageId}_{$tenantId}". Audit existing callers to confirm the right tenant context is passed.

4

Fixed retry sleeps, no 429 handling, no jitter

Rate-limit risk

Problem. Session-timeout retries use literal sleep(2) and sleep(5) at Api.php:122-127, 314-320, 330-336, 394-403. No exponential backoff, no jitter — under any kind of load spike, all retries hit BP at the same moment and amplify the spike. HTTP 429 (rate limit) is not detected at all on the REST path; we silently accept the failure and may retry-loop into a ban.

Cursor prompt

In Api::handle(), replace the fixed sleeps with exponential backoff + jitter: sleep(min(60, (2 ** $attempt) + mt_rand(0, 1000)/1000)). Detect HTTP 429 in the REST response branch and trigger the same retry loop with the documented carrier backoff (or default 30s) when a Retry-After header is present.

5

Null-safety gaps on API response data

Likely cause of "rare crashes"

Problem. Controller.php:459-475 and Service.php:1429-1446 chain methods on $response->data (.count(), .reject(), .first()) without checking $response->wasSuccessful() first. When auth retries silently produce a null payload, you get "Call to a member function count() on null" — usually filed as a one-off bug.

The REST path has the same shape (Api.php:297-323) — JSON unpacking assumes the structure is what we expect, no schema validation.

Cursor prompt

Audit every ->handle()->data chain in integrations/BenefitPoint/Controller.php and Service.php. Wrap each in a guard: if (!$response->wasSuccessful() || empty($response->data)) { /* surface error */ }. For REST operations, add a small helper that validates the expected JSON keys exist before accessing nested fields.

6

Hard-coded enum maps drift silently when Vertafore ships new product / rate types

Maintenance trap

Problem. Service.php:883-950 (the getBenefitType() switch on productTypeID), plus the static maps in ContributionData.php and RateData.php, hard-code BP's enum values. There's no validation that an incoming BP value is in the map. If Vertafore adds a new product type or renumbers a rate type, the parser silently maps to null or a default, and the data quietly stops flowing without anyone noticing.

Plansight's FindBPCodes command already exists to compare BP's GetProductTypes + GetRateTypes output against our hard-coded maps. It's just not run on a schedule.

Cursor prompt

Add a validating enum mapper to Service.php: mapBpEnum($value, array $map, string $context): ?string that logs a warning ("Unmapped BP enum {context}: {value}") when a value isn't in the map, then returns null. Use it in getBenefitType() and the equivalent helpers in ContributionData.php / RateData.php. Schedule FindBPCodes to run weekly and alert if maps have drifted.

7

Rate field copies and tier mismatches lose data without surfacing

Subtle

Problem. Service.php:1529-1597 (mapPlansightToBpRate) copies tier values between Plansight and BP rate shapes. Two issues: it mutates $destItem['valueNum'] from source values without validating type, range, or BP field constraints (so an out-of-range value silently propagates and BP rejects the eventual write); and when tier counts diverge between Plansight and BP (3-tier dental on our side, 5-tier on theirs), the fallback path quietly drops un-mapped tiers without logging.

Cursor prompt

In Service::mapPlansightToBpRate(): (a) validate copied valueNum values are numeric and within constraints from GetRateStructure before assignment, log + skip on mismatch; (b) when source and dest tier counts differ, log every dropped tier with source/dest IDs and surface a single user-facing warning per quote that data was incomplete.

Architecture-level questions

Five threads worth a 30-minute conversation with whoever owns BP integration. None are fixable in a single PR — they're decisions, not bugs.

Attribute ID reference

Every BenefitPoint attribute ID, in one place

Developer reference for the attribute IDs the BenefitPoint API uses across plans and benefit summaries. Each row pairs a BP attribute ID with its human label and the Plansight field it maps to. Source: the same data that drives the interactive Sync Map — re-extracted as a flat ctrl-F-friendly table.

124 attribute mappings across 8 benefit types. Each row pairs a BenefitPoint attribute ID with its human label and the Plansight field it maps to. Use browser find (Cmd-F / Ctrl-F) to locate by ID, name, or Plansight column.

BP IDBenefitPoint namePlansight fieldSync
Medical (46 attributes)
General Plan Information
45Annual Deductible/IndividualDeductibleIndividualSynced
44Annual Deductible/FamilyDeductibleFamilySynced
973Deductible Embedded or AggregateDeductibleTypeSynced
112Coinsurance — Push uses BP ID 295.HospitalFacilitySynced
386Office Visit/ExamPrimaryCareDoctorSynced
414Outpatient Specialist VisitSpecialistSynced
902TelemedicineTelehealthSynced
53Annual Out-of-Pocket Limit/IndividualOOPIndividualSynced
52Annual Out-of-Pocket Limit/FamilyOOPFamilySynced
873High Deductible Health Plan (HSA-eligible)hsaSynced
Preventive Services
974Preventive Care — BP section ID 455.PreventativeServicesSynced
975Preventive Screenings — Push uses 974.PreventativeServicesSynced
571Well-Child Care — Push uses 974.PreventativeServicesSynced
254Immunizations — Push uses 974.PreventativeServicesSynced
570Well Woman Exams — Push uses 974.PreventativeServicesSynced
339Mammograms — Push uses 974.PreventativeServicesSynced
16Adult Periodic Exams with Preventive Tests — Push uses 974.PreventativeServicesSynced
168Diagnostic X-Ray and Lab TestsDiagnosticSynced
971Complex RadiologyImagingSynced
Maternity Care
450Pregnancy and Maternity Care (Pre-Natal)MaternityOfficeSynced
Inpatient Hospital Services
295Inpatient HospitalizationHospitalFacilitySynced
439Pre-Authorization of Services RequiredN/A
503Semi-Private Room & Board (incl. services) — Push uses 295.HospitalFacilitySynced
Surgical Services
408Outpatient Facility ChargeOutpatientFacilitySynced
Emergency Services
184Emergency RoomEmergencyRoomCopaySynced
Urgent Care
555Urgent Care FacilityUrgentCareSynced
Mental Health
287Inpatient CareInpatientMentalSynced
407Outpatient CareOutpatientMentalSynced
Alcohol Abuse
294Inpatient Hospitalization — Push uses 670.InpatientSubstanceSynced
292Inpatient Detoxification Services — Push uses 670.InpatientSubstanceSynced
412Outpatient Services — Push uses 673.OutpatientSubstanceSynced
675Outpatient Detoxification Services — Push uses 673.OutpatientSubstanceSynced
Substance Abuse
670Inpatient HospitalizationInpatientSubstanceSynced
671Inpatient Detoxification Services — Push uses 670.InpatientSubstanceSynced
673Outpatient ServicesOutpatientSubstanceSynced
674Outpatient Detoxification Services — Push uses 673.OutpatientSubstanceSynced
Other Services and Supplies
174Durable Medical Equipment & Prosthetic DevicesMedicalEquipmentSynced
250Home Health CareHomeCareSynced
508Skilled Nursing or Extended Care FacilityNursingSynced
251Hospice CareHospiceSynced
Outpatient Rehabilitative Therapy
424PhysicalRehabilitationSynced
385Occupational — Push uses 424.RehabilitationSynced
515Speech — Push uses 424.RehabilitationSynced
Habilitative Services
877PhysicalHabilitationSynced
878Occupational — Push uses 877.HabilitationSynced
879Speech — Push uses 877.HabilitationSynced
Dental (17 attributes)
General Plan Information
44Annual Deductible/IndividualDeductibleIndividualSynced
45Annual Deductible/FamilyDeductibleFamilySynced
55Annual Plan MaximumAnnualMaxIndividualSynced
314Lifetime Orthodontia Plan MaximumLifetimeOrthoMaxSynced
Diagnostic and Preventive Services
390Oral ExamsExamsSynced
74Bitewing X-RaysXRaysSynced
109Cleaning and ScalingCleaningsSynced
Basic Services
64Basic FillingBasicFillingSynced
391Oral Surgery: Extractions and OtherOralSurgerySynced
190Endodontic TreatmentEndodonticsSynced
419Periodontic TreatmentPeriodonticsSynced
Major Services
137Crowns, Jackets and Cast Restoration BenefitsCrownsSynced
255ImplantsImplantsSynced
Orthodontia Services
392OrthodontiaOrthodonticsSynced
152Dependent ChildrenOrthodonticsAgeSynced
17Adults (and Covered Full-Time Students)OrthodonticsAdultSynced
314Adult Lifetime MaximumLifetimeOrthoMaxSynced
Vision (13 attributes)
General Plan Information
195ExaminationEyeExamsSynced
Benefit Frequency
194ExaminationExamFrequencySynced
309LensesLensesFrequencySynced
207FramesFramesFrequencySynced
122ContactsContactsFrequencySynced
Lenses
507Single Vision LensSingleVisionLensesSynced
73Bifocal LensBifocalLensesSynced
553Trifocal LensTrifocalLensesSynced
66Basic ProgressiveBasicProgressiveLensesSynced
Contact Lenses
356Medically NecessaryContactsNecessarySynced
178ElectiveContactsElectiveSynced
Frames
208Frame AllowanceFrameAllowanceSynced
Other Services
133Corrective Vision Services (e.g. Laser Surgery)LasikDiscountSynced
Basic Life (14 attributes)
Guarantee Issue Amount
187EmployeeOn Roadmap
Overall Maximum
188EmployeemaximumBenefit-1On Roadmap
Features
7Accelerated Benefit (Life Only)acceleratedDeathBenefitSynced
567Waiver of Premium (Life Only)premiumWaiverSynced
122Conversion (Life Only)conversionSynced
433PortabilityportabilitySynced
AD&D Schedule
497Seatbelt BenefitSynced
28Airbag BenefitairBagSynced
590Repatriation of RemainsrepatriationSynced
100Child Care BenefitchildCareSynced
Reduction of Benefits Schedule
2Tier 1 (Age 64 or Younger)Synced
3Tier 2 (65-69)Synced
4Tier 3 (70-74)Synced
5Tier 4 (75-79)Synced
STD (10 attributes)
Elimination Period
252Accidentwaiting_period_accidentSynced
505Sicknesswaiting_period_illnessSynced
8HospitalizationFirst Day HospitalSynced
General Plan Information
71Benefit PercentageSynced
569Weekly Benefit MaximumSynced
350Maximum Period of PaymentSynced
373Minimum Weekly BenefitSynced
142Definition of EarningsSynced
449Pre-Existing Condition LimitationsSynced
433PortabilityNot Synced
LTD (16 attributes)
General Plan Information
71Benefit PercentageltDisabilityBenefitSchedule-1Synced
582Guaranteed IssueltDisabilityGuaranteeIssueSynced
371Monthly Benefit MaximumltDisabilityMaximumMonthlyBenefit-1Synced
351Maximum Period of PaymentltDisabilityBenefitDurationSynced
374Minimum Monthly BenefitSynced
181Elimination PeriodltDisabilityEliminationPeriodSynced
466Recurrent DisabilitiesltDisabilityRecurrentProtectionSynced
142Definition of EarningsltDisabilityEarningsDefinitionSynced
801Earnings TestltDisabilityEarningsTestSynced
Limitations
365Mental IllnessltDisabilityMentalNervousSynced
526Substance AbuseltDisabilityAlcoholDrugSynced
501Self-ReportedSynced
449Pre-Existing Condition LimitationsltDisabilityPreExistingLimitationsSynced
Features
539Survivor BenefitltDisabilitySurvivorBenefitSynced
485100% Return to Work IncentiveSynced
113COLAltDisabilityCOLASynced
EAP (4 attributes)
Plan Design
384Number of Visits / In-person sessions per IssueeapInPersonSessionsIssueNot Synced
553Chemical Dependency / Drug & Alcohol CounselorsNot Synced
202Legal Resource and Referral / Financial CounselingNot Synced
557Utilization ReportingeapUtilizationReportsNot Synced
HRA (4 attributes)
Communication and Enrollment
192Enrollment MeetingsSynced
191Enrollment Kits / Startup KitsSynced
Compliance
170Discrimination TestingSynced
430Plan DocumentsSynced
Roadmap

What's next

Active work and open ideas. Tracked in JIRA project PS, refreshed continuously.

In Development

  • PS-8631 — Auto-populate primary renewal month from plan renewal dates
  • PS-8578 — Investigate rates not pushing on renewal/replacement plans
  • PS-8740 — EE+Spouse and EE+Child rates on Dental Renewals

Active Bug Work

  • PS-8697 — Base Life benefit fields completeness
  • PS-8693 — Voluntary Life ageBandGender enum casing
  • PS-8692 — Self-Funded Dental Rate Type ID mapping
  • PS-8691 — STD Rate Field 203 decimal precision
  • PS-8694 — Multi-plan summary modal handling

Recent Wins

  • PS-8541 — Renewals/replacements with multiple benefit summaries
  • PS-7674 — BP Plans Renew Only mode
  • PS-8587 — Federal Tax ID import fix
  • PS-8579 — Renewal rate dates correctly incremented
  • PS-8456 — Hotfix for null effective-date error

Ideas in Queue

  • PS-8675 — Broader BenefitPoint Attributes work
  • PS-8655 — Attribute Label customization
  • PS-8727 — Renewal-Only Clients mode
  • Migrate remaining SOAP operations to REST
  • Re-extract attribute code dictionary from current BP API