GUIDES
Requirement sets
Write each consumer's insurance rules as a versioned requirement set, and every surface check and verdict for that consumer is measured against the version in force. A requirement set is named by a key (default default). A consumer can carry several side by side, and an insured takes one engagement per key, so add a key when a consumer needs different rules for different insureds. Each engagement reads the version its key has bound to it.
Creating a version
Create the consumer first with PUT /consumers/{consumer_ref}. POST /consumers/{consumer_ref}/requirement-sets returns 404 for a consumer it does not know.
POST /consumers/{consumer_ref}/requirement-sets takes JSON:
| Field | What it is |
|---|---|
key |
Which of the consumer's requirement sets this version belongs to: lowercase letters, digits, - and _, up to 64 characters. A key not seen before starts a new one. Omitted, default |
rules |
The rules, shaped as below |
source_text |
The SOP as plain text, up to 200,000 characters, parsed into a draft. Send rules or source_text, one of the two |
name, reverification_cadence, expiry_lead_days, review_states |
Stored on the version. reverification_cadence defaults to quarterly, expiry_lead_days to 30 |
publish, applies_to, grace_period_days, effective_on |
Publish in the same call. applies_to is required when publish is true. Not accepted with source_text |
The response is 201 with the version object. Every version starts as a draft. Version numbers count per key: each requirement set starts at version 1, and (consumer_ref, key, version) names one version. The {version} routes below take an optional requirement_set query parameter, the key. Left off, they read the consumer's single set, or the one named default.
To parse an SOP file, send multipart/form-data with a source_document (PDF or DOCX) or a source_text field, plus an optional key. The draft carries parse_confidence per rule and ambiguities[], the places the SOP is too loose to enforce as written. Each ambiguity is an object: text, plus coverage_type, field and source (page, quote) when the parser can tell. The parser also keeps, for each rule, the source passage it read (page, quote), so the editor can show it next to the rule. Review the draft, then publish it. A multipart call with publish set returns 422.
A rule names a coverage type, the requirement, and two proof tests. Example:
{ "coverage_type": "auto_liability",
"requirement": {"kind": "limit_min", "label": "combined_single_limit", "min": 1000000},
"document_class_required": "coi", "verification_required": "broker",
"require_own_coverage": false, "reverification_cadence": "monthly", "severity": "hard" }
| Field | Values |
|---|---|
document_class_required |
The weakest document class you accept, from weakest to strongest: coi, endorsement, dec_page, policy. Default coi. A line below it reads unverified with reason document_class_below_required |
verification_required |
Who has to confirm the line: none, broker, or carrier. Default broker. broker accepts a broker or carrier confirmation, carrier accepts only a carrier, and a carrier_feed confirmation counts as carrier. An unconfirmed line reads unverified with reason verification_pending |
severity |
hard (default) or soft. hard rules decide status. soft results do not change it |
A rule that fails to compile, such as an unknown coverage_type or state code, is dropped and listed in compile_errors on the version. A version with compile_errors cannot be published.
Rule keys
Insurance Verified assigns the rule_key, and it is the key you see on every surface check and verdict. On a plain rule, a rule_key you send is replaced.
The shape is <coverage_type>.<requirement kind>, plus a suffix where the kind can repeat with different parameters.
| Requirement kind | Key | Example |
|---|---|---|
line_required |
<coverage_type>.line_required |
auto_liability.line_required |
limit_min |
<coverage_type>.limit_min.<limit label> |
general_liability.limit_min.each_occurrence |
endorsement |
<coverage_type>.endorsement.<name> |
auto_liability.endorsement.additional_insured |
occurrence_form |
<coverage_type>.occurrence_form.<value> |
general_liability.occurrence_form.occurrence |
expiry_min_days |
<coverage_type>.expiry_min_days |
cargo.expiry_min_days |
carrier_naic_allowlist |
<coverage_type>.carrier_naic_allowlist |
workers_comp.carrier_naic_allowlist |
certificate_text |
<coverage_type>.certificate_text.<field>.<hash> |
general_liability.certificate_text.description_of_operations.3f9a2c |
policy_form_accepted |
<coverage_type>.policy_form_accepted |
auto_liability.policy_form_accepted |
| Certificate holder | certificate.holder |
certificate.holder |
coverage_type is the canonical spelling: general_liability, auto_liability, workers_comp, occupational_accident, cargo, physical_damage, umbrella_excess, professional_eo, cyber, pollution, other. The short forms gl, al, auto, wc, oa, occ_acc, and umbrella are accepted and normalized to these.
An any_of rule keeps the rule_key you send. Left out, it defaults to the alternatives' coverage types joined by _or_, plus .any_of: workers_comp_or_occupational_accident.any_of.
What the certificate must show
The certificate holder is one rule for the whole set. Send it with "scope": "document" and no coverage_type:
{ "scope": "document", "severity": "hard",
"requirement": {"kind": "certificate_text", "field": "certificate_holder",
"match": "includes", "value": "Dropoff Logistics LLC"} }
| What you require | Shape | Checked against |
|---|---|---|
| Certificate holder | The rule above, once per set | The certificate's holder box, once per engagement. A miss fails the surface check with reason certificate_holder_mismatch. A source does not confirm this rule |
| Description of operations | certificate_text with field: "description_of_operations" on a coverage line |
That line's certificate, description of operations box |
| Anything else | certificate_text with field: "other" on a coverage line |
The certificate's full text: description of operations plus any free text read from it |
match is includes (default) or equals. Case, punctuation, and spacing are ignored.
Auto policy form
policy_form_accepted names the auto policy forms a consumer accepts. It applies to auto_liability and physical_damage lines. On any other coverage type, the rule is dropped and listed in compile_errors with code policy_form_wrong_coverage.
{ "coverage_type": "auto_liability", "severity": "hard",
"requirement": {"kind": "policy_form_accepted", "accepted": ["commercial"]} }
accepted lists any of commercial, personal_business_use, and personal, and defaults to ["commercial"]. Accepting personal also accepts personal_business_use. Insurance Verified reads a line's policy_form from the phrases printed on the document. A carrier's name alone does not set it.
| What the paper states | Rule reads | Surface check |
|---|---|---|
A form in accepted |
pass |
pass |
A form outside accepted |
fail with reason policy_form_not_accepted |
fail |
| No form, on any document class | unverified with reason policy_form_unconfirmed |
pass. The source confirms the form during verification |
When one rule covers several ways to comply
| Construct | Shape | Behavior |
|---|---|---|
| Alternatives | any_of: [ {coverage_type, requirement, …}, … ] in place of one coverage_type and requirement |
The rule takes the best result among its alternatives, and satisfied_by names the alternative that produced it. The common case is workers' compensation or occupational accident |
| State conditions | where: {"state_in": […]} or {"state_not_in": […]}, on a rule or on one alternative |
Applies only when the insured's state matches, and reads not_applicable otherwise. The state comes from insured_state on POST /documents, else from the end of the address set with PUT /insureds/{insured_ref}. With no state on file, the rule reads unverified with reason state_unknown |
| Review states | review_states on the set, default ["OH","ND","WA","WY"] |
When occupational accident wins an any_of rule for an insured in one of these states, the result keeps its outcome and carries state_review_required in flags and reasons |
A not_applicable result does not change the status.
Publishing
POST /consumers/{consumer_ref}/requirement-sets/{version}/publish takes applies_to, grace_period_days (default 14), and an optional effective_on. Only a draft with no compile_errors publishes. Anything else returns 409. The prior published version of the same key becomes superseded.
applies_to |
What changes |
|---|---|
new |
Engagements created from now on for this key bind to this version. Existing engagements keep the version they have, including an engagement with no version yet |
all_active |
Every active engagement following this key is rebound to this version, and Insurance Verified re-issues its surface check against the new rules in the same call |
A consumer's other keys, and their engagements, are untouched. GET /consumers/{consumer_ref}/requirement-sets lists every version across every key with its key, version, and status: draft, published, or superseded.
Before publishing all_active, call POST /consumers/{consumer_ref}/requirement-sets/{version}/preview with the same applies_to. It changes nothing and returns the impact:
| Field | What it is |
|---|---|
counts |
Engagements per bucket: newly_failing, newly_insufficient, unchanged, improved |
examples |
Up to 50 engagement ids per bucket |
rule_failure_counts |
Per rule_key, how many engagements fail it under the new version |
lines_needing_confirmation, lines_needing_confirmation_count |
Coverage lines whose confirmation is below the new rule's verification_required, up to 50 ids, and the total |
With applies_to: new, every bucket is empty. The publish response has the same shape plus engagements_rebound. Publishing queues requirement_set.published with consumer_ref, requirement_set (the key), version, applies_to, grace_period_days, effective_on, and impact, which holds the same counts.
Publishing opens no verification request. A request opens on a later cycle, one per coverage line per consumer, once the engagement's whole surface check passes.
Grace
When you publish all_active, each rebound engagement the impact places in newly_failing or newly_insufficient gets grace_until, set to the publish time plus grace_period_days. Read it on the engagement: GET /engagements/{engagement_id} returns grace_until alongside the surface check and the verdict.
grace_until is informational. The re-issued surface check carries the status the new rules produce, and no status changes when grace_until passes. The grace_until field on a verdict object is null.
A parent's coverage line counts toward a child's rule only when the child has no line of that coverage type and the parent line's
extends_to_childrenistrue. While it isnull, the rule readsunverifiedwith reasonparent_extension_unconfirmed. Setrequire_own_coverage: trueon a rule to count only the insured's own lines.