Skip to main content
Two endpoints. One async flow:
  1. SubmitPOST /api/v1/jobs
  2. PollGET /api/v1/jobs/{run_id}
No webhooks today. Persist run_id and poll.

What You Send

{
  "input": { },
  "offerings": [ ]
}
input is the insured profile and quote context. offerings is one line item per quoted home, auto, or umbrella option.

Input fields

input.coverage_types
array
required
Lines Nexio must satisfy: home, auto, umbrella.
input.address.state
string
required
Two-letter state code for deterministic filtering.
input.address.zip_code
string
required
ZIP code for property / garaging context.
input.drivers
array
required
Driver profiles.
input.vehicles_detail
array
required
Year, make, model, garaging ZIP, primary driver.
input.current_coverage
object
required
Incumbent home, auto, and umbrella policy details.
input.quotes
array
required
Package-level quote context from your brokerage workflow.
input.applicant
object
Named insured profile.
input.residence
object
Home underwriting context (sq ft, construction, renovation, replacement cost).
input.insurance_history
object
Continuous coverage, claims, lapses, non-renewals.

Coverage variants

coverage_types controls required lines:
  • Home only["home"], home offerings only
  • Home + auto["home", "auto"]
  • Home + auto + umbrella — adding umbrella makes it required
Extra offerings for categories not in coverage_types are ignored.

Offerings fields

One offering per quoted line item.
offerings[*].id
string
required
Stable line-level identifier.
offerings[*].provider_name
string
required
Carrier display name.
offerings[*].category
string
required
home, auto, or umbrella — must match a requested coverage type.
offerings[*].coverage.product_name
string
required
Quoted product or form name.
offerings[*].coverage.program_type
string
required
Use quoted_line for personal-lines offerings.
offerings[*].attributes.quote_id
string
required
Brokerage quote identifier for this line.
offerings[*].attributes.line_premium_annual
number
required
Annual premium for the line.
offerings[*].attributes.package_premium_annual
number
required
Annual premium for the parent package.

Converting Quotes to Offerings

If your source system has package quotes, map each line to one offering:
Source (input.quotes)Target (offerings[*])
carrierprovider_name
home / auto / umbrella line objectone offering per line with matching category
*.quote_idattributes.quote_id
*.premium_annualattributes.line_premium_annual
package_premium_annualattributes.package_premium_annual
package_idattributes.package_id (passthrough)
term_months, quote_generated_at, quote_expires_at, brokerattributes.* passthrough
Keep coverage_types and offerings[*].category aligned.

Quotes vs. offerings vs. solutions

  • input.quotes — package context your team already has
  • offerings — line-level inventory Nexio ranks
  • solutions — ranked packages Nexio returns
Nexio may return original single-carrier bundles or mixed-carrier packages assembled from your line items.

Submitting a Job

curl -X POST https://api.usenexio.com/api/v1/jobs \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer nx_test_YOUR_KEY" \
  -d '{
    "input": {
      "address": { "state": "CA", "zip_code": "92648" },
      "coverage_types": ["home", "auto", "umbrella"],
      "vehicles": 2,
      "premium": 12840
    },
    "offerings": [
      {
        "id": "quote_line_pure_home_001",
        "provider_name": "PURE",
        "category": "home",
        "coverage": { "product_name": "PURE Home", "program_type": "quoted_line" },
        "attributes": { "quote_id": "qt_pure_home_001", "line_premium_annual": 6480, "package_premium_annual": 13620 }
      },
      {
        "id": "quote_line_pure_auto_001",
        "provider_name": "PURE",
        "category": "auto",
        "coverage": { "product_name": "PURE Auto", "program_type": "quoted_line" },
        "attributes": { "quote_id": "qt_pure_auto_001", "line_premium_annual": 5160, "package_premium_annual": 13620 }
      },
      {
        "id": "quote_line_pure_umbrella_001",
        "provider_name": "PURE",
        "category": "umbrella",
        "coverage": { "product_name": "PURE Personal Excess Liability", "program_type": "quoted_line" },
        "attributes": { "quote_id": "qt_pure_umb_001", "line_premium_annual": 1980, "package_premium_annual": 13620 }
      }
    ]
  }'
Returns 202 Accepted:
{
  "run_id": "2aa8b3f1-9d11-4f4a-b2f2-6c2e3d96fdf0",
  "status": "queued"
}
Persist run_id immediately.

Polling for Results

Poll GET /api/v1/jobs/{run_id} until terminal.
StatusMeaningAction
queuedWaiting for workerKeep polling
processingPipeline runningKeep polling
completedResults readyConsume response
failedErrorRead error, stop
Start at 2s delay, backoff 1.5x, cap at 30s.
import time
import httpx

def wait_for_result(api_key: str, run_id: str) -> dict:
    headers = {"Authorization": f"Bearer {api_key}"}
    delay = 2

    while True:
        resp = httpx.get(f"https://api.usenexio.com/api/v1/jobs/{run_id}", headers=headers)
        resp.raise_for_status()
        data = resp.json()

        if data["status"] in ("completed", "failed"):
            return data

        time.sleep(delay)
        delay = min(delay * 1.5, 30)

Reading Results

{
  "run_id": "f912ee92-af38-4a4a-a49c-43ac089cc301",
  "status": "completed",
  "environment": "test",
  "output": {
    "diagnostic": null,
    "requirement_count": 3,
    "solutions_count": 6,
    "tolerance_bucket": "cost_sensitive",
    "top_label": "recommended",
    "top_score": 3.75
  },
  "solutions": [
    {
      "rank": 1,
      "cluster_label": "recommended",
      "provider_count": 1,
      "est_cost_low": 11985,
      "est_cost_high": 11985,
      "scorecard": { "overall_level": 3.75 }
    }
  ],
  "created_at": "2026-03-04T03:36:21Z",
  "completed_at": "2026-03-04T03:36:44Z"
}

Key fields

FieldPurpose
output.solutions_countRanked options produced
output.top_labelTop package label
output.top_scoreTop package score
solutions[*].rankRank order
solutions[*].cluster_labelrecommended, best_value, etc.
solutions[*].provider_count1 = single-carrier, 2+ = mixed
solutions[*].est_cost_low / est_cost_highAnnual cost range
solutions[*].scorecard.overall_levelCanonical package score
solutions[*].offerings[*].provider_nameCarrier per line
solutions[*].offerings[*].categoryhome, auto, umbrella
solutions[*].offerings[*].attributes.line_premium_annualLine premium

What NOT to expect

  • No solutions[*].carrier_name — use offerings[*].provider_name
  • No solutions[*].score — use scorecard.overall_level
  • No webhook or realtime metadata

Failure Cases

completed with 0 solutionsoutput.diagnostic may explain why. Common: coverage_types / offerings[*].category mismatch, missing required lines, or all offerings filtered out. Valid terminal state. failed — read error and error_details. Terminal. Stuck in processing — scorecards can take time in the EVALUATE stage. Use backoff.

Example Artifacts

example_input.json is the input value only. The submit body wraps it as { "input": ..., "offerings": [...] }.

Integration Checklist

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

Next Steps