+
Inbound integration with IDEON (rebranded from Vericred) — Plansight's primary source for ACA / individual market plan data, member rates, benefit summaries, and rating areas. Powers the small-group community-rated quoting workflow.
When Plansight quotes an ACA / community-rated plan, IDEON is where the rates come from, where the plan attributes are sourced, and where the benefit summaries are pulled. The integration imports carriers, syncs rates by rating area, and parses ~65 plan attributes into Plansight's standardized quote schema.
Detailed plan attributes (deductible, copays, coinsurance, OOP max, drug tiers, network info) keyed by HIOS ID. Benefit summary PDFs downloaded, virus-scanned, stored in S3.
Member rates queried by ZIP + FIPS county + rating area. Returns per-member premiums (age-banded) plus 4-tier composite premiums (Employee, ES, EC, Family).
Issuers list pulled from IDEON's S3 bucket (not API), filtered by state/year/quarter. Each new carrier creates a Carrier record + system user in Plansight.
ZIP-to-FIPS county lookup via GET /zip_counties. Cached in-memory per request. ACA rating areas keyed by FIPS + ZIP composite.
Vericred rebranded to IDEON a few years back. The Plansight codebase still uses the old name throughout — service classes, models, config keys.
app/Services/VericredParseService.php — main parserapp/Models/VericredRateId.php — rate ID cache modelapp/Helpers/Vericred.php — request dispatcher with retry logicconfig/vericred.apiKey, config/vericred.s3Key, config/vericred.s3Secret — config keysExternal-facing docs and conversations should use IDEON. Code references can stay as-is until a coordinated rename pass — these aren't broken, just dated.
Five distinct flows. Carriers and rating areas refresh on a schedule; rates and benefit summaries fetch on demand during quoting.
Pull issuers JSON from IDEON's S3 bucket (vericred-emr-workers) by state/year/quarter. Upsert to Carrier table keyed by HIOS ID. Create a plansightSystem user per new carrier.
For an ACA quote, Plansight calls GET /rates with ZIP + FIPS + rating area. Paginates through all per-plan rates. Stores results keyed by HIOS ID + plan option type.
For each rate ID, call GET /rates/{rateId}/member_rates. Correlate with census IDs. Store age-banded premiums per member and 4-tier composite premiums per coverage tier.
Plansight downloads the PDF, validates via ClamAV virus scan, uploads clean PDFs to Plansight's S3 at acaBenefitSummary/{hiosId}.pdf.
Map ZIP to FIPS county via GET /zip_counties. Cache the mapping in a static in-memory cache. ACA rating areas join FIPS county to a regulatory area code.
Simple API key in header for the REST API; separate AWS credentials for S3 fetches.
| Setting | Value / Source |
|---|---|
| Auth header | Vericred-Api-Key: {apiKey} |
| API base URL | https://api.vericred.com/ |
| API version header | Accept-Version: v8 |
| API key config | config/vericred.apiKey |
| HTTP client | Guzzle |
| Connection timeout | 15 seconds |
| Socket timeout | 60 seconds |
| Retry strategy | 4 attempts with exponential backoff (5s → 10s → 20s → 40s) |
| Retry triggers | ConnectException · HTTP 429 |
| S3 bucket | vericred-emr-workers (separate AWS creds) |
| File | Purpose |
|---|---|
app/Helpers/Vericred.php:32–233 | Main request dispatcher — pagination, retry, rate-limit handling |
app/Helpers/Vericred.php:235–263 | ZIP-to-FIPS mapping with in-memory cache |
app/Helpers/Vericred.php:291–439 | Member rate retrieval; age-banded + composite tier mapping |
app/Helpers/Vericred.php:441–551 | Carrier issuers import from S3 JSON |
app/Helpers/Vericred.php:617–710 | State data sync from S3 |
app/Services/VericredParseService.php:425–469 | Field map dispatcher — ~65 plan attributes |
app/Services/VericredParseService.php:855–1184 | Medical deductible / coverage string parser (regex-based) |
app/Services/VericredParseService.php:1532–1634 | Benefit summary PDF download, ClamAV scan, S3 upload |
app/Models/VericredRateId.php | Composite key model (rfpId + hiosIdPlanOptionType) |
app/Models/ACARate.php · ACARateRatingArea.php · ACARatingArea.php | ACA rate / rating-area models |
Lines 97–136 of Vericred.php implement 4-attempt retry with 5/10/20/40s delays for connection errors and HTTP 429. Sensible for transient timeouts and rate limits during heavy quote bursts.
VericredParseService uses a ~65-field map (lines 21–393) with pluggable parser functions. Covers benefit structure, tiers, cost-share, special cases, and ACA metadata.
Lines 985–1084 use regex to extract cost-share from human-readable strings like "In-Network: $250 / Out-of-Network: 50% after deductible." Fragile but necessary for unstructured benefit summaries.
PDFs validated via ClamAV (lines 1587–1617) before storage. Prevents serving infected PDFs back to brokers / clients in proposals.
Carrier issuers and state data fetched from IDEON's S3 bucket, not from the API. Decouples the rate engine from API throughput.
Static $zipToFipsCache speeds repeated lookups within a request. Not shared across requests.
A walkthrough of the field-map dispatcher (~61 attributes) and the regex-based cost-share parser that handles free-text strings like "In-Network: $25 / Out-of-Network: 50% after deductible". The parser favors robustness over elegance — it preserves the raw IDEON string for every field as an audit trail and falls back to type Other rather than dropping data.
Vericred.php lines 32–233: request() retrieves plan JSON with pagination, retries (4 attempts, exponential backoff), and rate-limit handling.
VericredParseService.php lines 425–469: parse() iterates the $fieldMap array, dispatching each of ~61 IDEON attributes to a specialized parser (medicalDeductible, medicalRx, tfToYn, etc.). Fields prefixed aca bypass the vericredData tracking object.
Most cost-share fields call parseMedicalDeductibleCoverageString() (lines 964–1184), the core regex engine. Simple fields use one-liners like tfToYn (boolean → "Yes"/"No") or textStraight (pass-through).
benefitSummaryDownload() lines 1532–1634: downloads the PDF, validates with ClamAV, uploads to S3 at acaBenefitSummary/{hiosId}.pdf. Failures return empty string silently — see "Things to verify" below.
Each parser returns an array of {field, value} pairs. The dispatcher accumulates them and populates the Quote model. Every parsed field also writes a sibling aca{FieldName} with the raw IDEON string for audit.
Grouped by category. The 28 service-cost-share fields share a single parser (medicalDeductible) — listed once with the full set, since the mapping shape is identical.
| IDEON field | Plansight field(s) | Parser | Transformation |
|---|---|---|---|
| Plan metadata (10 fields) | |||
display_name | name | textStraight | Pass-through |
actuarial_value | inNetworkActuarialValue | actuarialValue | In-network only; out-of-network defaults to 0 |
level | acaLevel | textStraight | Bronze / Silver / Gold / Platinum |
network_name | inNetworkNetwork | textStraight | Pass-through |
hios_issuer_id | hiosCarrierId | textStraight | Pass-through |
type | vericredType | textStraight | Plan type from Vericred enum |
plan_type | medicalPlanType | medicalPlanType | Maps to config enum; defaults to "No Selection" if unrecognized |
effective_date | acaEffectiveDate + rateGuaranteeDateRangeFrom | textStraight | Duplicated to both fields |
expiration_date | acaExpirationDate + rateGuaranteeDateRangeTo | textStraight | Duplicated to both fields |
benefits_summary_url | acaBenefitSummaryFile | benefitSummaryDownload | Download → ClamAV scan → S3 upload; empty string on failure |
| Deductibles & OOP max (8 fields) | |||
individual_medical_deductible | {in,out}NetworkDeductibleIndividual* | medicalDeductible | Multi-network parse: value, type ($/%/Other), and deductible flag (AD/ND) |
family_medical_deductible | {in,out}NetworkDeductibleFamily* | medicalDeductible | Same shape as individual |
individual_medical_moop | {in,out}NetworkOOPIndividual* | medicalDeductible | Multi-network parse |
family_medical_moop | {in,out}NetworkOOPFamily* | medicalDeductible | Multi-network parse |
individual_drug_deductible | {in,out}NetworkRxIndividualDeductible | rxMoneyDeductible | Includes deductible-required flag (Yes / No / Major Medical / Not Covered) |
family_drug_deductible | {in,out}NetworkRxFamilyDeductible | rxMoneyDeductible | Family flag intentionally suppressed (line 1322) |
embedded_deductible | {in,out}NetworkDeductibleType | embeddedAggregate | "embedded" → Embedded · "non_embedded" → Aggregate · else blank |
plan_calendar | {in,out}NetworkDeductibleOopAccumulation | calendarPlanYear | "calendar_year" → Calendar Year · else → Plan Year |
Service cost-share (29 fields, all use medicalDeductible except ER) | |||
All twenty-eight standard service-cost-share IDEON fields route through medicalDeductible and produce the same 4-sibling shape per network: value, Type ($/%/Not Covered/N/A/Range/Unlimited/Other), Ded (AD/ND), and Other (free-text fallback). | |||
primary_care_physician · specialist · preventative_care · diagnostic_test · imaging · outpatient_facility · outpatient_physician · ambulance · urgent_care · inpatient_facility · inpatient_physician · outpatient_mental_health · inpatient_mental_health · outpatient_substance · inpatient_substance · prenatal_care · inpatient_birth_physician · inpatient_birth · home_health_care · rehabilitation_services · habilitation_services · skilled_nursing · durable_medical_equipment · hospice_service · child_dental · child_eyewear · child_eye_exam · chiropractic_services · coinsurance
| |||
emergency_room ★ | {in,out}NetworkEmergencyRoom* | erDeductible (special) | Detects "plus" for copay+coinsurance and splits into separate copay and coinsurance fields; sets copay type to $ when % coinsurance is present |
| Pharmacy / Rx (9 fields) | |||
generic_drugs | {in,out}NetworkRxTier1* | medicalRx | Tier 1 — label "Generic" |
nonpreferred_generic_drug_share | {in,out}NetworkRxTier2* | medicalRx | Tier 2 — label "NP Gen." |
preferred_brand_drugs | {in,out}NetworkRxTier3* | medicalRx | Tier 3 — label "Brand" |
non_preferred_brand_drugs | {in,out}NetworkRxTier4* | medicalRx | Tier 4 — label "NP Brand" |
specialty_drugs | {in,out}NetworkRxTier5* | medicalRx | Tier 5 — label "Spec." |
nonpreferred_specialty_drug_share | {in,out}NetworkRxTier6* | medicalRx | Tier 6 — label "NP Spec." (Plansight enforces a 6-tier ceiling) |
mail_order_rx | {in,out}NetworkRxMailOrder | inOutTextStraight | Same value to both networks |
formulary_name | {in,out}NetworkRxBenefitFormulary | inOutTextStraight | Same value to both networks |
drug_formulary_url | {in,out}NetworkRxBenefitFormularyURL | inOutURL | Validates with filter_var(); empty if invalid |
| Network behavior & flags (3 fields) | |||
gated | {in,out}NetworkSpecialistReferral | tfToInOutReq | Boolean → Yes / No (true = referral required) |
telemedicine | {in,out}NetworkTelehealth* | telehealth | Empty → "Not Covered"; non-empty → "Included" |
hsa_eligible | hsa | tfToYn | Boolean → Yes / No |
Field suffixes — * denotes the parser returns multiple sibling fields per attribute: the value, Type, Ded (AD/ND), and (when applicable) Other for free-form fallback or To for ranges. The raw IDEON string is also written to a sibling aca{FieldName} as an audit trail.
parseMedicalDeductibleCoverageString() at lines 964–1184 is the heart of the integration. It takes IDEON's free-text cost-share strings and extracts numeric values, types, deductible flags, and ranges. This is where most parsing bugs live and where most "Other"-type fallbacks come from.
The parser splits the input string by network section using three labels:
$sections = [
'inNetwork' => 'In-Network:',
'in2Network' => 'In-Network-Tier-2:',
'outNetwork' => 'Out-of-Network:',
];
For each section, regex preg_match('/' . preg_quote($label, '/') . '\s*([^\/]*)/', $ideonStr, $matches) at line 975 captures everything from the label to the next /. The captured chunk is then run through type detection, deductible-flag detection, and special-pattern handlers.
| Type | Detection | Notes |
|---|---|---|
$ Range | regex /\$(\d[\d,]*)\s*-\s*\$(\d[\d,]*)/i | Captures both ends of a dollar range. Stores value + valueTo. |
$ or % | Both symbols present → first by strpos() wins | Brittle when IDEON writes "$25 or 50%" — $ wins regardless of intent |
Not Covered / N/A | Substring check on cleaned value | Forces Ded = ND |
Unlimited | Substring check | Used for preventive-style "no cost" services |
Other | Fallback when nothing else matches | Preserves the original string for manual review |
stripos($value, 'after deductible') !== false ? 'AD' : 'ND'. Simple substring check, case-insensitive./first\s+(\d+)\s+(?:visit\(s\)|day\(s\))\s*\$?([\d,]+)(?:[^\S\r\n]*then[^\S\r\n]*\$?([\d,]+%?))?/i captures first-visit copay and optional "then" coinsurance. Reconstructs as (count)$amount then Y%. Type forced to Other.+. Type forced to Other.$ and value ends with "per day", overrides type to Other and preserves the full string.$cleanVal = explode('|', $cleanVal)[0] — silently drops alternate clauses after a |.inNetwork and in2Network sections appear, they're merged into a flattened display like $30 / $25 AD / 25% AD / 50% AD. Hard to audit on re-read.| Input string | Parsed result |
|---|---|
In-Network: $30 / Out-of-Network: 50% | in: type=$, value=30, ded=ND out: type=%, value=50, ded=ND |
In-Network: $50 after deductible / Out-of-Network: Not Covered | in: type=$, value=50, ded=AD out: type=Not Covered, ded=ND |
In-Network: $500 - $2000 / Out-of-Network: $3000 - $4000 | in: type=$ Range, value=500, valueTo=2000 out: type=$ Range, value=3000, valueTo=4000 |
In-Network: first 2 visit(s) $30 then 20% / Out-of-Network: 40% | in: type=Other, value="(2)$30 then 20%" out: type=%, value=40, ded=ND |
In-Network: $25 plus 10% coinsurance / Out-of-Network: 30% | in: type=Other, value="$25+10% coinsurance" out: type=%, value=30, ded=ND |
In-Network: Unlimited / Out-of-Network: Unlimited | in: type=Unlimited, ded=ND out: type=Unlimited, ded=ND |
strpos() position (lines 995-1001): First symbol wins. "$25 or 50%" parses as $-typed with value 25, even if the percentage was the intended primary.parseDeductible() maps Unknown → type "N/A". parseRxMoney() maps Unknown → ded='No' (non-deductible). Different code paths, different semantics.[digits] visit(s)|day(s). Variations like "first visit $25, then $10" (no count) won't match.Other, the deductible flag appends. If the source already says "AD", you get $30 AD AD.Other fallback (line 1013): Anything that doesn't match $/%/range/special-pattern silently becomes type=Other with no log. Strings like "based on procedure" pass through unflagged.This is a data integration layer, not a clean room. The parser favors preservation over precision — it errs toward Other when uncertain and keeps the raw IDEON string in aca{FieldName} sibling fields so a human can sanity-check downstream. That's the right call for an inbound feed where IDEON's format may evolve, but it does mean the proliferation of Other-typed values in production reports is a signal that some IDEON formats remain outside the regex coverage. Worth a quarterly grep against the live data to surface unrecognized patterns.
A scan of IDEON's documented medical-plan response against our parser, with corrections from the team applied. Every row below is a field IDEON exposes that Plansight genuinely doesn't read today (or doesn't read in this form). Twelve fields, grouped by category. The phasing block at the bottom shows where to start.
| IDEON field | What it is | Why we'd want it | Priority |
|---|---|---|---|
| Plan identification (3 fields) | |||
id | IDEON's stable internal plan ID | Survives across renewals; the right key for caching, delta-sync, and reconciliation | High |
plan_id | Carrier's internal plan code | What the carrier uses on their side — broker-facing for support tickets and "this isn't the same plan" conversations | Medium |
marketing_name / plan_marketing_name | Consumer-facing display name | The legal name (which we read as display_name) and the marketing name diverge for many carriers. Brokers want the marketing name on proposals | Medium |
| Documents & URLs (2 fields) | |||
provider_directory_url | Direct link to the carrier's provider search | Massive UX win on customer-facing proposals — brokers love being able to drop "search for your doctor" links | High |
formulary_url | Direct link to the drug formulary PDF | We read drug_formulary_url (a legacy alias). Should also pull the canonical formulary_url for consistency | Medium |
| Marketplace & subsidies (3 fields) | |||
on_marketplace | Boolean — plan is available on Healthcare.gov / state exchange | Critical for PTC subsidy eligibility logic. Today we infer this from other signals (carrier + plan_type) — fragile | High |
off_marketplace | Boolean — plan available outside the exchange only | Counterpart to on_marketplace. Some plans are dual-listed; we should surface that | High |
csr_variant_id | Cost Sharing Reduction variant (73 / 87 / 94 silver) | Without this, we can't surface the right CSR plan for subsidy-eligible families. CSR plans are different SKUs of the same Silver plan with reduced deductibles / OOP — easy to miss | High |
| Network identifier (1 field) | |||
network_id / network_ids | Identifier(s) for the plan's provider network | Currently we read network_name (string). The ID is the stable handle for cross-referencing with bulk endpoints. Required for the bulk-load architecture (Gap #4) | Medium |
| Pre-tax account flags (2 fields) | |||
hra_eligible | Boolean — Health Reimbursement Account compatible | Sibling to hsa_eligible we already read. Cheap to add | Medium |
fsa_compatible | Boolean — Flexible Spending Account compatible | Sibling to hsa_eligible. Cheap to add | Low |
| Member contact (1 field) | |||
customer_service_phone | Member services phone number | Standard on plans. Useful in proposal footers and "what to do next" leave-behinds | Low |
Confirmed by the team — these IDEON fields look like gaps on paper but are already handled today, either directly or via an equivalent flow:
benefits_summary_url, downloads, virus-scans, converts to its own S3-hosted version, and serves that. The official SBC content is captured.actuarialValue parser.medicalPlanType.Phase 1 (highest leverage, shortest paths): id, on_marketplace + off_marketplace, csr_variant_id, provider_directory_url. Five fields, all single-line additions to the field map. Unblocks subsidy-correctness and gives brokers a new URL to surface in proposals.
Phase 2 (architecture-aligned): network_id. Directly enables the bulk-load architecture in Gap #4 — without it, even if we cache plans we can't reliably resolve them by network.
Phase 3 (polish): marketing_name, plan_id, formulary_url, hra_eligible, fsa_compatible, customer_service_phone. Cheap to add once Phase 1 is done; not worth a separate sprint.
Three specific gaps from comparing our integration to the IDEON docs. Each is the cause of a real production issue, and each is a fixable change rather than a structural rewrite.
Problem. Level-funded plans are deliberately excluded from /bulk/plans and /bulk/pricings because they're risk-rated per-group based on census. They only come through the Quote API: POST /quotes → poll GET /quotes/{id} until status == "complete" → GET /quotes/{id}/rates. Our current architecture (bulk catalog + per-call /rates) bypasses this path entirely, so level-funded is structurally invisible to us. From the docs: "The Quoting API is asynchronous for Level Funded Quotes. You can use the status field to poll until it is complete."
Fix. Add a parallel Quote API path used only when the broker requests level-funded. Keep the existing /rates path for ACA / community-rated. The level-funded rate response includes claims_surplus_fraction, stop_loss_amount, claims_fund (monthly claims reserve), and fixed_costs (admin/stop-loss fees). Persist the Quote ID + payload against the RFP so subsequent broker views don't re-quote.
In app/Helpers/Vericred.php, add a getLevelFundedQuote($groupId, $effectiveDate, $productLine) method that POSTs to /quotes, polls GET /quotes/{id} until status == 'complete' (timeout 60s, 2s interval with backoff), then GETs /quotes/{id}/rates. Store the response keyed by RFP ID. Add a feature flag RFP_FETCH_LEVEL_FUNDED to gate it. Reference: docs.ideonapi.com → Group Quoting → Level Funded.
Problem. When a broker uploads a 7-person census and assigns members to current plans (e.g. 5 on Plan A, 1 on Plan B, 1 on Plan C), Plansight submits each plan-option as a separate sub-group quote. UHC's enrolled-lives minimum kicks in for the 1-person Plan B and Plan C sub-groups, returning no rate even though the actual group is 7 people and clears the minimum easily.
Fix. Stop fragmenting the census before quoting. Submit the full 7-person census to IDEON for every plan we want priced. Compute per-plan "real-world enrollment" cost locally by summing GET /rates/{rate_id}/member_rates for just the members the broker assigned to that plan. From the docs: "Rates are broken down by Member and Dependent, so that you can show the final cost in different scenarios where an employer might cover a different percentage." The intended pattern is one quote per plan, then enrollment-scenario math locally.
Find every place a sub-group census is submitted to Vericred::getRates(). Refactor to submit the full census once per plan. Compute per-plan enrollment cost locally from GET /rates/{rate_id}/member_rates by summing the rates of members assigned to that plan in the RFP. Verify on a known UHC group that today returns no rate due to sub-group minimums.
/limiting_factors — silent rejectionsProblem. When IDEON rejects a plan due to a carrier business rule (minimum enrolled lives, participation, geography, age constraints, etc.), Plansight doesn't surface why. The broker just sees a missing rate with no explanation, which makes Gap #2 (above) particularly painful to debug. From the docs: "information... when there is a business rule that prevents one or more plan from being quoted."
Fix. After each quote, call GET /quotes/{id}/limiting_factors and surface per-plan rejection reasons in the quote view (carrier, plan ID, the rule that fired). Combined with Gap #2, this turns "no rate" into "Plan B unavailable: UHC requires 5 enrolled lives" or similar.
Add Vericred::getLimitingFactors($quoteId) calling GET /quotes/{id}/limiting_factors. Parse the response into per-plan rejection reasons (carrier, plan ID, business rule). Surface in the quote view as a tooltip or inline footnote on plans that didn't return rates.
Problem. Today, every ACA / community-rated quote calls GET /rates, paginated, per quote. That's a per-broker, per-RFP cost — both in latency (long page-throughs of rate data) and in carrier-imposed rate-limit risk. We chose this architecture early because UnitedHealthcare requires per-call quoting (see Gap #1) — but UHC is the exception, not the rule. For the other carriers, the data we need lives in IDEON's bulk endpoints already.
The opportunity. IDEON's bulk endpoints (/bulk/plans, /bulk/pricings, /bulk/rating-areas, /bulk/zip-counties, /bulk-exports) collectively give us everything needed to determine rating area + quarter + plans + rates from flat files alone for non-level-funded, non-UHC plans. With those cached locally (refreshed quarterly when IDEON publishes new bulk data), Plansight could let a broker drop a new plan into a customer's profile without hitting IDEON's API at all.
What "loading a plan as a new plan" looks like under this model. Broker chooses a customer, types/searches for a plan (Plansight surfaces options from the local bulk cache), Plansight resolves rating area from the customer's ZIP+FIPS, picks the appropriate quarter's rates, and instantiates the plan + member rates locally. Zero API calls, instant response. Bulk refresh is a quarterly ETL pipeline against POST /bulk-exports → poll GET /bulk-exports/{id} → ingest the resulting payload into Plansight tables.
What still requires the API. UHC level-funded (Gap #1 — Quote API). Anything where we need real-time per-group risk-adjusted pricing. Bulk gives us the catalog; the API is for the subset of pricing that's group-specific.
Scope a BulkSync job that runs quarterly: calls POST /bulk-exports/plans-in-bulk, polls GET /bulk-exports/{id}, downloads the resulting bulk payload, and ingests into local tables (BulkPlan, BulkRate, BulkRatingArea, BulkZipCounty). Then add VericredBulkService::loadPlanFromCache($hiosId, $zip, $effectiveDate) that resolves the plan + rates from local cache without an API call. Gate behind a BULK_PLAN_LOADING feature flag. Validate parity against a known-good API-fetched plan as a regression check.
If level-funded forces us into the Quote API anyway, should we move all rate fetching to the Quote API? Trade-offs: stay on /rates = bulk catalog still works, no async polling for ACA, two code paths. Move to /quotes = all product lines unified, composite tiers come server-side (delete local code), CSR/CHIP/PTC subsidies come for free, limiting-factors endpoint becomes available everywhere.
Recommendation: add the Quote API path for level-funded now, leave /rates for ACA/community-rated for the moment, and plan a consolidation pass later. That avoids a big-bang rewrite while unblocking UHC level-funded.
Static-read findings. The integration works in production; these are areas where edge cases or maintenance attention would pay off.
Complex regex patterns make many assumptions about format ("first X visit(s)", "plus", "per day"). If IDEON varies format, parsing may silently fail or misinterpret values. Worth fixture-based unit tests.
Lines 1098–1150 merge in2Network and inNetwork results. Logic is convoluted — checks for "%", conditionally adds symbol, checks for "up to". Hard to audit for edge cases.
Lines 1575–1616 catch exceptions during PDF download and virus scan, returning empty field instead of failing hard. Quote may be created with missing benefit summary without alerting the broker.
HIOS ID is used as primary key / filename with no validation (line 1549). Unusual IDs could cause filesystem issues. Defensive check worth adding.
$zipToFipsCache is never cleared. Long-running batch processes could serve stale data if a ZIP's FIPS mapping changes mid-run.
For large rate payloads or slow network, 60s socket timeout (Vericred.php:34) could be exceeded. The 4-attempt retry mitigates but the timeout is worth reviewing.