Skip to main content
You are viewing legacy endpoint documentation. See the Modern docs for engine-scoped endpoints.
This guide covers what the API reference doesn’t: how to structure your carrier quotes for Nexio and interpret the results. For request/response schemas, see Submit Job and Get Job Status.

Flow

Persist run_id. Polling remains the canonical reconciliation path even when using webhooks.

What you send

{
  "input": { ... },
  "offerings": [ ... ]
}
input is the insured’s profile (applicant, address, drivers, vehicles, residence, current policies). offerings is one entry per carrier quote per coverage line (home, auto, umbrella).
input.current_coverage describes incumbent policies. It provides context for scoring but does not replace the offerings array.

Building offerings from your quotes

Each carrier quote becomes one offering per coverage line. If you have 3 carriers quoting home, auto, and umbrella, that’s 9 offerings (3 carriers x 3 lines). Keep offerings[*].category aligned with input.coverage_types. Extra offerings for categories not in coverage_types are ignored.

Multi-carrier input

When comparing packages from multiple carriers, submit offerings from each. The engine evaluates all valid combinations — both single-carrier bundles and mixed-carrier packages:
{
  "input": {
    "address": { "state": "NY", "zip_code": "11231" },
    "coverage_types": ["home", "auto", "umbrella"],
    "appetite_bucket": "balanced",
    "vehicles": 1,
    "premium": 3557.23
  },
  "offerings": [
    {
      "id": "quote_line_carrier_a_home_001",
      "provider_id": "prov_carrier_a",
      "provider_name": "Carrier A",
      "category": "home",
      "quality_rating": "A+",
      "pricing_tier": "premium",
      "commission": 0.14,
      "constraints": { "excluded_states": [], "prohibited_naics": [], "avoided_naics": [] },
      "coverage": { "product_name": "Select Homeowners", "program_type": "quoted_line" },
      "attributes": { "quote_id": "qt_carrier_a_home_001", "line_premium_annual": 6120, "package_premium_annual": 12840 }
    },
    {
      "id": "quote_line_carrier_b_home_001",
      "provider_id": "prov_carrier_b",
      "provider_name": "Carrier B",
      "category": "home",
      "quality_rating": "A",
      "pricing_tier": "economy",
      "commission": 0.12,
      "constraints": { "excluded_states": [], "prohibited_naics": [], "avoided_naics": [] },
      "coverage": { "product_name": "Select Home", "program_type": "quoted_line" },
      "attributes": { "quote_id": "qt_carrier_b_home_001", "line_premium_annual": 5050, "package_premium_annual": 10950 }
    }
  ]
}
Results may include an all-Carrier A bundle, an all-Carrier B bundle, and mixed-carrier combinations (e.g. Carrier A home + Carrier C auto) — all ranked by composite scorecard.

Polling

Poll GET /api/v1/jobs/{run_id} until terminal. Start at 2s delay, backoff 1.5x, cap at 30s.
StatusAction
queuedKeep polling
processingKeep polling
completedConsume solutions
failedRead error, stop
import time, httpx

def wait_for_result(api_key: str, run_id: str) -> dict:
    headers = {"Authorization": f"Bearer {api_key}"}
    delay = 2
    while True:
        data = httpx.get(f"https://api.usenexio.com/api/v1/jobs/{run_id}", headers=headers).json()
        if data["status"] in ("completed", "failed"):
            return data
        time.sleep(delay)
        delay = min(delay * 1.5, 30)

Reading results

Key fields on a completed response:
FieldPurpose
solutions[*].rankRank order (1 = best)
solutions[*].cluster_labelSolution label: recommended, best_value, best_coverage, simplest
solutions[*].scorecard.overall_levelPackage score (lower is better)
solutions[*].provider_count1 = single-carrier, 2+ = mixed
solutions[*].est_cost_low / est_cost_highAnnual cost range
solutions[*].offerings[*].provider_nameCarrier per line
solutions[*].offerings[*].categoryhome, auto, umbrella
There is no solutions[*].carrier_name — use offerings[*].provider_name. There is no solutions[*].score — use scorecard.overall_level.

Failure cases

completed with 0 solutionsoutput.diagnostic explains why. Common causes: coverage_types / offerings[*].category mismatch, missing required lines, or all offerings filtered out. This is a valid terminal state, not an error. failed — read error and error_details. Terminal. Stuck in processing — the EVALUATE stage can take time. Use backoff, don’t tight-loop.

Integration checklist

  1. offerings generated per quoted line, not per package
  2. offerings[*].category aligns with input.coverage_types
  3. Polling handles all four status values
  4. Package score read from scorecard.overall_level
  5. Carrier identity read from offerings[*].provider_name
  6. Both request and terminal response persisted

Example artifacts