quote_insurance
Purpose: generate instant, itemized quote estimates from the carriers
Foresee supports, across the lines and states Foresee currently serves,
in one call — the LIVE TODAY line at the end of this description names
today's set.
`lines` is REQUIRED and is ONE map: each key names a line to price (e.g.
"auto", "renters", "home" — plain words are fine), each value is that
line's coverage ask as actual numbers. A line Foresee doesn't quote in
the user's state comes back under `skipped`: `lines` names each one and
`message` is one sentence, written to be relayed to the user as-is,
naming what Foresee does quote in that state. For auto
the ask has four axes — `bi` (bodily-injury liability, per-person/
per-accident in $000s, e.g. "100/300"), `pd` (property-damage liability in
$000s, e.g. 100), `coll_deductible` (collision deductible in dollars, e.g.
500) and `comp_deductible` (comprehensive deductible in dollars, e.g.
500); `um` and `medpay` are optional. A renters ask has four axes —
`coverage_c` (personal-property/contents limit in dollars, e.g. 30000),
`coverage_e` (personal liability in dollars, e.g. 100000), `coverage_f`
(guest medical in dollars, e.g. 1000) and `deductible` (all-perils, in
dollars, e.g. 500); `coverage_d` is optional. A home ask: `coverage_a`
(the dwelling's replacement cost in dollars), `coverage_e` (e.g. 300000),
`coverage_f` (e.g. 1000) and `aop_deductible` (all-other-perils
deductible in dollars, e.g. 1000). There are no named coverage levels
and the server never defaults: pass exact numbers. An omitted OPTIONAL
axis (`um`, `medpay`, `coverage_d`) keeps each carrier's own
default — the quote's per-coverage lines show what was rated. Any
numbers at or above the state's legal minimum work as the ask (an auto
`bi`/`pd` below it prices nothing — no carrier may sell that policy — and
comes back under `coverage_required` naming the minimum); each carrier's
`price_ladder` prices every other rung, so a starting
selection is easy to refine after the fact. An incomplete ask on a
live line prices nothing and answers with `coverage_required` naming that
line's own axes; an axis supplied with a value no carrier offers (`bi`
"banana", a negative deductible) is refused the same way, naming the bad
value and the format the axis takes. Each supported carrier is priced at
the selection given; a carrier that doesn't offer an asked rung is priced
at its nearest offered one and says so: its entry carries
`rated_vs_asked` (per axis: `asked`, `rated`, and `coverage` "less"/"more"
than asked; the dense text puts it on the `C` row as `rated`). That price is NOT
like-for-like — state the rated limits next to it every time you show it
(e.g. "$255/mo — 30/60 BI / $25k PD, the most this carrier offers, not
the 100/300 / $100k you asked for"), and never let it headline or anchor
a cheapest/spread claim without saying so. A carrier Foresee can't price
appears in `failures` with the reason, as does one Foresee can't price
for a line it was asked on (no program served there yet, or the carrier
doesn't sell that line in the state) — a carrier never silently vanishes
from a line's results. Priced results come back per line under
`by_line`.
Profile requirements: ZIP code, age (or dob) and — for auto — each
vehicle's year/make/model are REQUIRED; they have no server-side
fallback. A missing or mistyped one errors at the schema with guidance;
a value that fits the schema but cannot rate ("not-a-zip", a negative
age) comes back in `profile_required` naming it, with guidance on what
the field takes. Use the profile schema's exact field names: a key the
schema doesn't name is carried but never rated. A complete call — a
25-year-old in Oakland with a 2021 Civic, a January 2025 speeding ticket
and a 2023 at-fault accident, asking for 100/300 BI, $100k PD and $500
collision/comprehensive deductibles:
{"profile": {"zip_code": "94621", "age": 25, "auto": {"drivers": [{"violations": [{"on": "2025-01", "kind": "speeding"}], "accidents": [{"on": "2023-06-15", "at_fault": true, "amount": 4200}]}], "vehicles": [{"year": 2021, "make": "Honda", "model": "Civic"}]}}, "lines": {"auto": {"bi": "100/300", "pd": 100, "coll_deductible": 500, "comp_deductible": 500}}}
Every violation needs `kind` and `on`, every accident `on`; an
incomplete entry is refused naming its path, never assumed away.
Each carrier returns a **point estimate**
(`monthly`) plus a `confidence_interval` that reflects only what's genuinely
unresolvable (irreducible), NOT missing profile fields. A field the caller
omits is filled with ONE declared value and reported in `assumptions` /
`tighten_by` (the reducible "tell us X and we sharpen" gap) — the response
is built to be presented early and refined, never widened into
a vague range. Each entry's `field` is the exact profile path to send
the user's real answer under (e.g. `auto.drivers[].violations`), and
`tighten_by` lists those same paths. The one exception is
`incident_details`: it is answered by completing the incident entries
already sent (dates, fault, BI split), not under a fresh key.
Each carrier's `quote` carries every sub-coverage line (BI/PD/collision/
comprehensive/UM…) with its monthly price, at the selection you passed (echoed
as `coverage_selection`). Most carriers also carry a `price_ladder`: for each
coverage lever of the line (auto: BI limit, PD limit, collision/comprehensive
deductible; renters: deductible and the C/E/F limits; home: AOP deductible
and the A/E/F limits) the exact
price at every rung, one lever moved at a time with everything else
held at the user's selection — the ladder is anchored at the selection you
passed, so its `anchor.monthly` is the carrier's `monthly`. It answers
limit/deductible what-ifs with real marginal prices.
Every ladder number IS an exact re-rate; a combined change or an unlisted
rung has no derivable price (rating is not linear), so those price only
through a re-call with the new `coverage_selection`. A profile what-if
(a cleaner record, another vehicle, a different ZIP) prices the same way:
re-call with the changed profile.
RESULT FORMAT: compact machine text on `dense`, one section per line. Each section opens Q <state> <line> sel=<the coverage_selection priced, as JSON>. assumptions:, tighten_by:, input_flags: and not_rated: carry those fields; each entry's `field` (and each tighten_by item) is the profile path to send the user's answer under, and `incident_details` is answered by completing the incident entries already sent. not_priced: <carrier>,…:<reason> ; … is the line's `failures`, grouped by reason. skipped <line>,…: <message> names the lines not quoted in this state. Row types — C: carrier|entity|monthly|ci lo-hi, then |rated <axis>=<rung>(asked <X>,less|more);… when the price is for a rung other than the ask (`rated_vs_asked`). W: a warning on the carrier above. L: monthly $ per coverage line (already monthly, every carrier), under codes that mean the same coverage at every carrier: BI PD UMBI UIMBI UMPD MEDPAY PIP COLL COMP RENTAL TOWING GAP; A+B is one premium covering both (BI+PD); FEE is a flat fee; any other code is a coverage only that carrier sells. D <lever> <selected>=option:±$: the change in the carrier's monthly for each option of that lever, everything else held at the selection; <selected>(asked <X>) means X is not an option and the price sits at the selected rung — answer deductible/limit what-ifs from D without another call (new monthly = monthly + delta). Only state numbers that appear in the result or follow from monthly + a D delta; if a rung is not in D for a carrier, say the carrier has no such option rather than guessing.
When the user wants firm numbers straight from the carriers, offer live carrier quotes: Foresee agents complete the carriers' real quote flows via live_carrier_quotes (which explains the required disclosure + consent affirmation; no sign-in is needed). Instant quotes stay the first answer; live quotes are the follow-up.
LIVE TODAY: Foresee quotes auto in CA today.