Agent Integration Guide
The Agentic Flow API is a conversational quoting API for commercial insurance. Send a message describing a business and coverage need; the service returns a real-time stream of events that drives the quoting workflow — enriching business data, identifying eligible carriers, collecting required application answers, and retrieving live carrier quotes. Brokers interact with the service through a sequence of turns: each turn produces streaming events, and some turns require a broker response before the workflow continues.
This guide covers everything a client application needs: authenticating requests, starting and resuming conversations, consuming the event stream, responding to broker checkpoints, receiving quotes, and handling errors.
Part 1 — Integration Guide
1. Quick Start
All requests go to a single endpoint that returns a stream of Server-Sent Events (SSE):
POST /agentic-flow/chat/stream
Accept: text/event-stream
The API supports two request formats:
JSON — text-only request:
curl -X POST https://<host>/agentic-flow/chat/stream \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-b "auth-alpha=<your-session-token>" \
-d '{"message": "Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215"}'
import requests
response = requests.post(
'https://<host>/agentic-flow/chat/stream',
headers={'Content-Type': 'application/json', 'Accept': 'text/event-stream'},
cookies={'auth-alpha': '<your-session-token>'},
json={'message': 'Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215'},
stream=True,
)
Multipart — with a document attachment:
curl -X POST https://<host>/agentic-flow/chat/stream \
-H "Accept: text/event-stream" \
-b "auth-alpha=<your-session-token>" \
-F "message=Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215" \
-F "document=@acord_application.pdf"
import requests
with open('acord_application.pdf', 'rb') as f:
response = requests.post(
'https://<host>/agentic-flow/chat/stream',
headers={'Accept': 'text/event-stream'},
cookies={'auth-alpha': '<your-session-token>'},
data={'message': 'Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215'},
files={'document': ('acord_application.pdf', f, 'application/pdf')},
stream=True,
)
The first two events in the response are always:
event: start
data: {"session_id": "a3f9c2b1-...", "status": "started"}
event: run_id
data: {"run_id": "a3f9c2b1-..."}
session_id (in the start event), run_id (in the run_id event), and the x-session-id response header are all the same value. Save it — include it as run_id in every subsequent request to continue this conversation.
run_id = response.headers.get('x-session-id') # available before any event arrives
2. Authentication
The API accepts two independent forms of credential. Either is sufficient on its own — use whichever fits your integration.
| Credential | How you obtain it | How you send it |
|---|---|---|
| Bearer token | Client-credentials grant against the BP Auth API — see Authenticate | Authorization request header |
Session cookie (auth-alpha) | Interactive login through the BP Login app. Not obtainable via API — there is no programmatic endpoint for this token. | auth-alpha cookie |
Bearer token
Request a token from the BP Auth API using the client_credentials grant, then send it as a standard Authorization header on every request:
Authorization: bearer_<your-token>
See Authenticate for the token endpoint, request parameters (grant_type, client_id, client_secret), and response shape. Tokens obtained this way expire after 12 hours, same as session cookies — re-authenticate to get a fresh one.
Example — cURL:
curl -X POST https://<host>/agentic-flow/chat/stream \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-H "Authorization: bearer_<your-token>" \
-d '{"message": "Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215"}'
Example — Python:
import requests
response = requests.post(
'https://<host>/agentic-flow/chat/stream',
headers={
'Content-Type': 'application/json',
'Accept': 'text/event-stream',
'Authorization': 'bearer_<your-token>',
},
json={'message': 'Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215'},
stream=True,
)
Session cookie
There is no API to obtain the auth-alpha cookie. It is issued only after an interactive login through the BP Login app — your client must complete that login flow (e.g. in a browser) and then read the resulting cookie for use in subsequent API calls.
Include the session token as a cookie on every API request.
Cookie format:
Cookie: auth-alpha=<jwt-token>
The cookie key is auth-alpha by default. Confirm with your environment if a different prefix is in use.
Example — cURL:
curl -X POST https://<host>/agentic-flow/chat/stream \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream" \
-b "auth-alpha=<your-session-token>" \
-d '{"message": "Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215"}'
Example — Python:
import requests
response = requests.post(
'https://<host>/agentic-flow/chat/stream',
headers={
'Content-Type': 'application/json',
'Accept': 'text/event-stream',
},
cookies={'auth-alpha': '<your-session-token>'},
json={'message': 'Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215'},
stream=True,
)
Auth error responses:
| Status | Reason |
|---|---|
401 | Missing cookie, expired session, or invalid token |
403 | Valid session but the run_id belongs to a different user |
503 | Auth service is unreachable |
3. Starting a Conversation
All requests go to a single endpoint:
POST /agentic-flow/chat/stream
Content-Type: application/json # text-only requests
Content-Type: multipart/form-data # document uploads
Accept: text/event-stream
The response is always a Server-Sent Event stream. The session ID is returned in the x-session-id response header before any event arrives.
The API supports two conversation modes:
| Quote Flow | STP Flow | |
|---|---|---|
| Trigger | Business name and address in message | Application ID marker in message |
| Starting point | New quote from scratch | Existing application in the platform |
| Carrier selection | Service identifies eligible carriers; broker confirms | Auto-selects best available carrier |
| Critique / validation | awaiting_critique_review — enriched business data flagged for broker review before application is created | awaiting_naics_validation — NAICS code validated post-CQS; auto-approved unless a critical discrepancy is found |
| Broker gates | More checkpoints (enrichment review, data quality, carrier confirmation, application answers, post-quote) | Fewer gates — most steps are automated |
| Document upload | Supported (attach ACORD form, loss run, etc.) | Not applicable |
3.1 Quote Flow (by business name and address)
Send any message with a business name and address. The service enriches the business, validates data, creates an application, identifies eligible carriers, collects any required answers, and returns quotes. At key decision points the service pauses and waits for broker input before continuing.
{
"message": "Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215"
}
3.2 STP Flow (by application ID)
To process an application that already exists in the platform, include the application ID marker in the message. The service reads the existing application, validates it, auto-selects the best available carrier, and returns a quote — with fewer manual steps than the Quote Flow path.
{
"message": "[APPLICATION_ID_MODE: 550e8400-e29b-41d4-a716-446655440000] Get a GL quote"
}
Marker format: [APPLICATION_ID_MODE: <uuid>]
3.3 Resuming a paused conversation
When the service pauses at a decision point, resume by posting run_id plus either action_id (shorthand) or resume_options (explicit).
Using action_id (recommended):
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "confirm_application",
"payload": {}
}
Using resume_options (explicit):
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"message": "",
"resume_options": {
"confirm_application": true
}
}
4. Streaming Responses
The service streams responses as Server-Sent Events (SSE). Each event uses the wire format:
event: <event_name>
data: <json_payload>
(Two trailing newlines separate events.)
Consuming the stream:
import json
import requests
response = requests.post(
'https://<host>/agentic-flow/chat/stream',
headers={'Content-Type': 'application/json', 'Accept': 'text/event-stream'},
cookies={'auth-alpha': '<your-session-token>'},
json={'message': 'Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215'},
stream=True,
)
session_id = response.headers.get('x-session-id') # available before any event
run_id = None
buffer = ''
for chunk in response.iter_content(chunk_size=None, decode_unicode=True):
buffer += chunk
while '\n\n' in buffer:
event_str, buffer = buffer.split('\n\n', 1)
event_name = None
data_str = None
for line in event_str.splitlines():
if line.startswith('event:'):
event_name = line[6:].strip()
elif line.startswith('data:'):
data_str = line[5:].strip()
if not event_name or not data_str:
continue
payload = json.loads(data_str)
if event_name == 'start':
pass # stream open
elif event_name == 'run_id':
run_id = payload['run_id']
elif event_name == 'content':
print(payload['content'], end='', flush=True)
elif event_name == 'subagent_content':
print(f"[progress] {payload['content']}")
elif event_name == 'application':
pass # update application state
elif event_name == 'eligible_carriers':
print(f"Eligible carriers: {payload}")
elif event_name == 'quotes':
print(f"Quotes received: {payload}")
elif event_name == 'hitl_pause':
print(f"Gate: {payload['pipeline_stage']}")
# send resume request using run_id
elif event_name == 'done':
run_id = payload.get('run_id', run_id)
elif event_name == 'error':
raise RuntimeError(payload['error'])
elif event_name == 'complete':
pass # stream closed
5. End-to-End Examples
Quote Flow
Pipeline plan:
| Step | What the service does | Broker gate |
|---|---|---|
| 1. Enrich | Looks up business data — NAICS, revenue, employee count, address validation | — |
| 2. Critique review | Flags enriched data issues for broker attention | awaiting_critique_review — approve or correct |
| 3. Application creation | Creates the insurance application from the enriched data | — |
| 4. Carrier matching | Identifies eligible carriers and presents them for confirmation | awaiting_carrier_confirmation — confirm the list |
| 5. Data quality check | Flags conflicting or ambiguous fields for broker resolution (if needed) | awaiting_user_input — resolve or skip |
| 6. Application questions | Collects any required fields the service could not pre-fill | awaiting_application_answers — submit answers |
| 7. Application review | Presents the completed application for final broker sign-off | awaiting_application_review — approve or correct |
| 8. Quoting | Retrieves live quotes from the confirmed carriers | — |
| 9. Post-quote action | Broker takes a final action on the quotes | awaiting_post_quote_actions — bind, download, or finish |
Turn sequence:
Turn 1 — Start:
POST /agentic-flow/chat/stream
{"message": "Get a GL quote for ABC Plumbing, 123 Main St, Columbus, OH 43215"}
Key events: start → run_id → subagent_content → mkt_intel → eligible_carriers → hitl_pause (awaiting_critique_review) → done → complete
Turn 2 — Approve enriched data:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "approve_critique",
"payload": {}
}
Key events: start → run_id → application → hitl_pause (awaiting_carrier_confirmation) → done → complete
Turn 3 — Confirm carriers:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "confirm_application",
"payload": {}
}
Key events: start → run_id → application → hitl_pause (awaiting_application_answers) → done → complete
Turn 4 — Answer application questions:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "submit_answers",
"payload": {
"mqs_ins_history_3yr_catchall": "No",
"mqs_currently_insured": "Yes"
}
}
Key events: start → run_id → quotes → hitl_pause (awaiting_post_quote_actions) → done → complete
Turn 5 — Post-quote action:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "bind",
"payload": {}
}
Key events: start → run_id → content → done (pipeline_stage: null) → complete
The turn sequence above shows a typical happy path. Gates like awaiting_user_input and awaiting_application_review appear only when the service detects issues that need broker attention.
STP Flow
Pipeline plan:
| Step | What the service does | Broker gate |
|---|---|---|
| 1. Load application | Reads the existing application from the platform | — |
| 2. Carrier auto-selection | Selects the best available carrier automatically — no broker confirmation required | — |
| 3. CQS | Collects carrier-specific questions for the selected carrier | awaiting_application_answers — submit answers |
| 4. Quoting | Retrieves live quotes from the selected carrier | — |
| 5. NAICS validation | Validates the NAICS industry code post-CQS | awaiting_naics_validation — only if a critical discrepancy is detected; auto-approved otherwise |
| 6. Post-quote action | Broker takes a final action on the quotes | awaiting_post_quote_actions — bind, download, or finish |
Turn sequence:
Turn 1 — Start with application ID:
POST /agentic-flow/chat/stream
{"message": "[APPLICATION_ID_MODE: 550e8400-e29b-41d4-a716-446655440000] Get a GL quote"}
Key events: start → run_id → application → eligible_carriers → quotes → hitl_pause (awaiting_post_quote_actions) → done → complete
Turn 2 — Post-quote action:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "bind",
"payload": {}
}
Key events: start → run_id → content → done (pipeline_stage: null) → complete
Part 2 — API Reference
6. Request Schema
ChatRequest
| Field | Type | Required | Description |
|---|---|---|---|
message | string | No | The broker's message. May be empty when resuming at a gate. |
run_id | string | No | Existing session ID to resume. Also accepted as session_id. Omit to start a new session. |
resume_options | ResumeOptions | No | Gate-resume parameters. See below. |
action_id | string | No | Shorthand resume action. Takes precedence over resume_options when provided. Enum: approve_critique, reply_critique, confirm_application, submit_answers, submit_corrections, proceed_without_corrections, approve_application_review, get_quotes, bind, download, done |
payload | object | No | Data accompanying an action_id (e.g. answers map, carrier list). |
ResumeOptions
Supply only the fields relevant to the current gate (pipeline_stage in the hitl_pause or done event).
| Field | Type | Gate | Description |
|---|---|---|---|
confirm_application | boolean | awaiting_carrier_confirmation | Confirm the presented carrier list. |
critique_reply | string | awaiting_critique_review, awaiting_naics_validation | Broker reply to data quality findings. Empty string ("") approves as-is. |
application_answers | object | awaiting_application_answers | Map of { question_code: answer } for unanswered questions. |
review_corrections | object[] | awaiting_application_review | List of { question_code, answer, carrier? } corrections. null means approve as-is. |
corrections | object | awaiting_user_input | Field corrections for a discrepancy. E.g. {"payroll": 50000}. |
proceed_without_corrections | boolean | awaiting_user_input | Skip corrections and proceed. |
get_quotes | boolean | awaiting_quote_selection | Fetch live quote status from carriers. |
add_carriers | string[] | Any | Add additional eligible carriers to the quoting pipeline. |
user_id | string | Any | Audit identifier for the responding user. Defaults to "user". |
7. Response Headers
| Header | Description |
|---|---|
x-session-id | Session ID for this request. Same value as run_id in the run_id event. Available before any stream event. |
Content-Type | text/event-stream |
Cache-Control | no-cache |
8. Event Schemas
All events use the SSE wire format:
event: <name>
data: <json>
Event summary
| Event | When it fires | What to do |
|---|---|---|
start | First event of every response | Stream is open; ignore or show a loading indicator |
run_id | Second event of every response | Save run_id — required to resume this session |
content | While the assistant is replying | Concatenate and display to the broker |
subagent_content | While the service is processing | Show as a progress update |
application | After application data is ready | Snapshot of the current application |
eligible_carriers | After carrier matching | Array of carrier names eligible to quote |
mkt_intel | After carrier recommendation | Carriers likely to bind, with reasoning summary |
quotes | After live quotes are fetched | Quote status and pricing from carriers |
hitl_pause | At a broker checkpoint | Pause and prompt the broker — see below |
done | Last event of every turn | Turn complete; check pipeline_stage to decide next step |
error | On a terminal failure | Display the error; start a new session |
complete | After done | Stream closed; ignore |
hitl_pause
The service has paused and is waiting for broker input. This is the most important event to handle — the session will not advance until you resume it.
{
"run_id": "string",
"pipeline_stage": "string",
"resume_hint": {},
"ui_component": {}
}
| Field | Type | Notes |
|---|---|---|
run_id | string | Include in the resume request |
pipeline_stage | string | Which checkpoint is active — see enum below |
resume_hint | object | The exact resume_options shape expected to unblock this gate |
ui_component | UIComponentSpec | Self-describing UI spec for rendering the checkpoint controls |
pipeline_stage values:
| Value | Flow | Description |
|---|---|---|
awaiting_critique_review | Quote | Broker reviews enriched business data before application creation |
awaiting_carrier_confirmation | Quote | Broker confirms the list of eligible carriers |
awaiting_application_answers | Quote | Broker answers outstanding application questions |
awaiting_user_input | Quote | Broker resolves conflicting or ambiguous data |
awaiting_application_review | Quote | Broker reviews the completed application before carrier submission |
awaiting_naics_validation | STP | NAICS code validated post-CQS on existing application (auto-approved unless discrepancy detected) |
awaiting_quote_selection | Both | Broker triggers live quote fetch from carriers |
awaiting_post_quote_actions | Both | Broker takes a post-quote action (bind, download, etc.) |
done
Signals the end of a turn. Always check pipeline_stage — if non-null the session is paused and the broker must act before the next turn.
{
"run_id": "string",
"final_response": "string",
"pipeline_stage": "string | null",
"ui_component": {}
}
| Field | Type | Notes |
|---|---|---|
run_id | string | Persist — use in every subsequent request |
final_response | string | The assistant's full text reply for this turn |
pipeline_stage | string \| null | Active gate stage (see enum above), or null when the conversation is complete |
ui_component | UIComponentSpec | Gate UI spec when pipeline_stage is non-null |
UIComponentSpec
Each hitl_pause and done event carries a ui_component object so your client can render the correct checkpoint controls without hardcoded gate logic.
{
"gate_type": "awaiting_carrier_confirmation",
"title": "Confirm Carriers",
"description": "Please confirm the carriers before submitting the application.",
"props": {
"selected_carriers": ["Carrier A", "Carrier B"]
},
"actions": [
{
"action_id": "confirm_application",
"label": "Confirm & Proceed",
"variant": "primary",
"payload": {}
}
]
}
| Field | Type | Notes |
|---|---|---|
gate_type | string | Matches pipeline_stage. Use this to determine which checkpoint is active. Enum values match the pipeline_stage table above. |
title | string | Human-readable heading for the checkpoint UI |
description | string | Optional explanatory text |
props | object | Checkpoint-specific display data (carrier list, questions, etc.) |
actions[].action_id | string | The value to POST as action_id to resume. Enum: approve_critique, reply_critique, confirm_application, submit_answers, submit_corrections, proceed_without_corrections, approve_application_review, get_quotes, bind, download, done |
actions[].label | string | Display label for the action button |
actions[].variant | string | Button style: primary, secondary, destructive |
actions[].form | object[] | When present: render a form; user-entered values go in payload |
9. Error Codes
HTTP errors
| Status | Cause | Action |
|---|---|---|
400 | Request blocked by content guardrails | Surface the detail field to the user |
401 | Missing or expired session cookie | Re-authenticate via BP Auth |
403 | run_id belongs to a different user | Do not retry with this run_id |
503 | Auth service unreachable | Retry with exponential backoff |
error SSE event
Emitted on terminal failures. The stream ends after this event. Start a new session by omitting run_id.
event: error
data: {"error": "Processing failed — please try again"}
Health check
GET /agentic-flow/health
{"status": "ok", "agent": "ready"}
"agent": "initializing" means the service is still loading — wait before sending requests.
Part 3 — Behavioral Specification
10. Conversation Lifecycle
A session (identified by run_id) is created on the first request and persists across multiple request/response turns. Sessions are stateful — each turn continues exactly from where the last turn ended.
Turn 1: POST {message} → events → paused at gate A
Turn 2: POST {run_id + action} → events → paused at gate B
Turn 3: POST {run_id + action} → events → conversation complete (pipeline_stage: null)
Sessions are persisted and can be resumed at any time using the same run_id. The authentication token expires after 12 hours — re-authenticate to obtain a new token before resuming a session after a token expiry.
11. Event Ordering
Within a single turn, events are emitted in this order:
Guarantees:
startis always first;completeis always last.run_idalways immediately followsstart.hitl_pausealways precedesdonein the same turn.donealways precedescomplete.
No ordering guarantees among content, subagent_content, application, eligible_carriers, and quotes within a turn.
12. Broker Checkpoints
At key decision points the service pauses, emits a hitl_pause event, and waits for broker input. The session remains open and its state is persisted — there is no timeout on individual checkpoints.
The hitl_pause payload contains everything needed to resume:
pipeline_stage— which checkpoint is activeui_component— a self-describing specification for rendering the checkpoint UIresume_hint— the exactresume_optionsshape to send
Resume by POSTing run_id and the appropriate action_id or resume_options.
Gate: awaiting_critique_review
The service reviewed the business data and flagged potential issues for broker attention. The broker must respond before the application is created.
Resume — approve as-is:
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "approve_critique", "payload": {}}
Resume — with feedback:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "reply_critique",
"payload": {"feedback": "The revenue is correct. Please update NAICS to 238220."}
}
Gate: awaiting_carrier_confirmation
The service has identified eligible carriers. The broker confirms the list before the application is submitted.
hitl_pause sample payload:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"pipeline_stage": "awaiting_carrier_confirmation",
"resume_hint": {"confirm_application": true},
"ui_component": {
"component": "awaiting_carrier_confirmation",
"gate_type": "awaiting_carrier_confirmation",
"title": "Confirm Carrier List",
"props": {"selected_carriers": ["CHUBB", "Acuity Insurance", "Travelers"]},
"actions": [
{"action_id": "confirm_application", "label": "Confirm & Submit", "variant": "primary", "payload": {}}
]
}
}
Resume:
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "confirm_application", "payload": {}}
Gate: awaiting_application_answers
The service requires answers to application questions it could not pre-fill.
hitl_pause sample payload:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"pipeline_stage": "awaiting_application_answers",
"resume_hint": {"application_answers": {"mqs_ins_history_3yr_catchall": "No", "mqs_currently_insured": "Yes"}},
"ui_component": {
"component": "awaiting_application_answers",
"gate_type": "awaiting_application_answers",
"title": "Application Questions",
"props": {
"questions": [
{
"question_code": "mqs_ins_history_3yr_catchall",
"question_text": "Has this business had a lapse of coverage, been declined, canceled, or non-renewed in the last 3 years?",
"type": "select",
"options": ["Yes", "No"]
},
{
"question_code": "mqs_currently_insured",
"question_text": "Do you currently have insurance for this business?",
"type": "select",
"options": ["Yes", "No"]
}
]
},
"actions": [
{
"action_id": "submit_answers",
"label": "Submit Answers",
"variant": "primary",
"payload": {},
"form": [
{"name": "mqs_ins_history_3yr_catchall", "type": "select", "label": "Coverage history (last 3 years)", "required": true, "options": ["Yes", "No"]},
{"name": "mqs_currently_insured", "type": "select", "label": "Currently insured?", "required": true, "options": ["Yes", "No"]}
]
}
]
}
}
Resume:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "submit_answers",
"payload": {"mqs_ins_history_3yr_catchall": "No", "mqs_currently_insured": "Yes"}
}
Gate: awaiting_user_input
The service found conflicting or ambiguous data and needs the broker to resolve it before proceeding.
Resume — with corrections:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"message": "",
"resume_options": {"corrections": {"payroll": 75000, "employee_count": 12}}
}
Resume — proceed without corrections:
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "proceed_without_corrections", "payload": {}}
Gate: awaiting_application_review
The completed application is presented for final review before submission to carriers.
Resume — approve as-is:
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "approve_application_review", "payload": {}}
Resume — with corrections:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "submit_corrections",
"payload": {
"review_corrections": [
{"question_code": "mqs_estimated_annual_revenue", "answer": 2200000},
{"question_code": "mqs_full_time_employees", "answer": 11, "carrier": "Acuity Insurance"}
]
}
}
Gate: awaiting_naics_validation
(STP Flow only.) After the CQS step, the service validates the NAICS industry code against the existing application. Auto-approved when no critical issue is found; pauses for broker input only when a critical discrepancy is detected.
Resume — approve:
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "approve_critique", "payload": {}}
Resume — with correction:
{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "reply_critique",
"payload": {"feedback": "Please update NAICS to 238220 (Plumbing Contractors)."}
}
Gate: awaiting_quote_selection
Quotes have been retrieved from carriers. The broker reviews pricing.
Resume — refresh quote status:
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "get_quotes", "payload": {}}
Gate: awaiting_post_quote_actions
Quoting is complete. The broker chooses a next action.
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "bind", "payload": {}}
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "download", "payload": {}}
{"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95", "action_id": "done", "payload": {}}
Gate summary
pipeline_stage | Mode | Description | action_id options |
|---|---|---|---|
awaiting_critique_review | Quote Flow | Data quality review before application is created | approve_critique, reply_critique |
awaiting_carrier_confirmation | Quote Flow | Confirm carrier list before application is submitted | confirm_application |
awaiting_user_input | Both | Resolve data discrepancies | provide_corrections, proceed_without_corrections |
awaiting_application_answers | Both | Answer unanswered application questions | submit_answers |
awaiting_application_review | Both | Final review of completed application | approve_application_review, submit_corrections |
awaiting_naics_validation | STP Flow | NAICS validation (auto-approves if no critical issue) | approve_critique, reply_critique |
awaiting_quote_selection | Both | Quotes received; broker reviews pricing | get_quotes |
awaiting_post_quote_actions | Both | Post-quote: bind, download, or finish | bind, download, done |
13. Quote Lifecycle
The service may perform enrichment, document analysis, data validation, and carrier quote retrieval before the conversation completes. Progress is communicated through streaming events throughout.
- Session starts — broker sends a message (Quote Flow or STP Flow).
- Enrichment and validation — the service gathers and validates business data; issues are surfaced via
awaiting_critique_reviewif broker input is needed. - Application — an application is created or the existing one is validated; checkpoints are emitted as
applicationevents. - Carrier identification — eligible carriers are identified and emitted via
eligible_carriers. The broker confirms (Quote Flow) or the service auto-selects (STP Flow). - Application questions — any unanswered required fields are collected via
awaiting_application_answers. - Quoting — the service retrieves quotes from carriers; results are emitted via
quotesevents. - Post-quote — the broker chooses a final action via
awaiting_post_quote_actions.
14. Reconnection and Retry
Dropped SSE connection
If the SSE connection drops mid-stream, reconnect immediately using the last run_id received:
{"run_id": "a3f9c2b1-...", "message": ""}
The service will re-emit the current hitl_pause event if the session is paused at a gate.
Idempotency
Resume requests with the same run_id and action_id are safe to retry — the service will not double-process a gate that has already been passed.
Retry guidelines
| Condition | Recommended action |
|---|---|
503 HTTP | Retry with exponential backoff (start 1 s, cap 30 s) |
error SSE event | Start a new session (omit run_id) |
401 HTTP | Re-authenticate and retry |
403 HTTP | Do not retry — wrong run_id for this user |
| Dropped SSE connection | Reconnect immediately with the same run_id |
15. Token Expiration
Sessions are persisted and can be resumed at any time — there is no session TTL. Only the authentication token expires.
The authentication token (auth-alpha cookie) is valid for 12 hours. After expiry:
- Requests return a
401HTTP response. - Re-authenticate to obtain a fresh token.
- Resume the existing session using the same
run_idwith the new token — no data is lost.
Part 4 — FAQ
16. Frequently Asked Questions
1. How do I know when the conversation is complete?
Check pipeline_stage in the done event at the end of every turn. When it is null, the workflow has finished and no further input is needed. When it is non-null, the session is paused at a broker checkpoint and must be resumed before the next turn begins.
2. What happens if I don't respond to a broker checkpoint?
Nothing — there is no timeout on broker checkpoints. The session is persisted and can be recovered at any time using the same run_id.
3. Can I have multiple concurrent conversations?
Yes. Each conversation is an independent session with its own run_id. There is no limit on the number of active sessions per user.
4. Can multiple users share a run_id?
No. A run_id is bound to the authenticated user who created it. Any request using a valid token but referencing another user's run_id returns a 403 response.
5. How long are sessions retained?
Sessions are persisted and can be resumed at any time — there is no session TTL. The authentication token expires after 12 hours; re-authenticate and then resume the existing session using the same run_id. No conversation data is lost when a token expires.
6. Can I cancel an in-progress request?
Close the SSE connection at any time to stop receiving events. The session remains open server-side at whatever stage it reached and can be resumed using the last run_id received. There is no explicit cancel API.
7. Do I need to handle every event type?
No. For basic flow control you only need to act on two events: hitl_pause (pause and prompt the broker) and done (check pipeline_stage to decide the next step). All other events — content, subagent_content, application, eligible_carriers, mkt_intel, quotes — are informational and can be displayed or ignored depending on your UI needs.
8. Can I upload multiple PDFs in a single request?
Partially, we support a single file at a document but you can zip up multiple documents and submit that i.e. ACORD, Loss Runs, Supplementals etc. zipped up.
9. What happens if a carrier declines or doesn't return a quote?
The workflow continues with the remaining carriers. A declined or non-responsive carrier is reflected in the quotes event with an appropriate status. The broker can still take post-quote actions on any quoted carriers — a single carrier failure does not block the session.
10. How are failures handled mid-turn?
The service emits an error SSE event and the stream ends. Session state is preserved at the last completed checkpoint — resume with the same run_id to retry from that point. For auth failures (401), re-authenticate and retry with the same run_id — the session is preserved.
Part 5 — Agents
17. Market Intelligence Agent
The Market Intelligence (MI) agent (mkt_intel_agent) predicts which carriers are most likely to return a quote for the risk, and surfaces those recommendations to the broker. Where carrier matching answers "who is allowed to quote this risk?", the MI agent answers "who should we quote, how likely are they to bind, and at roughly what price?"
It runs as a mkt_intel step in both pipeline plans. In the Quote Flow the broker reviews the MI recommendation at awaiting_carrier_confirmation before carriers are quoted; in the STP Flow the carrier-select step automatically picks the top-ranked carrier from the MI output with no broker confirmation. The MI step runs after the critique and master-question steps complete — these are declared predecessors, so it does not start until they finish.
What it does
- Reads the enriched business summary and the full application from session state, along with the requested product(s). The agent can use any datapoint on the application as context — not just NAICS, state, and product — and forwards the available firmographic and risk-eligibility fields to the model.
- Requests market intelligence predictions for each coverage product.
- Cross-references the predictions against the carriers eligible to quote on the application.
- Persists the result to session state, which emits the
mkt_intelSSE event (see the Event Summary in §8).
What the market intelligence model reasons over
The MI agent is a client of the Market Intelligence ML service, which ranks carriers and estimates premiums with per-carrier models. The service uses a dual-model architecture and auto-routes based on how much application data is available — so the more of the application the agent passes, the richer the prediction:
| Model | Inputs | When used |
|---|---|---|
| Base | product, NAICS description, state | Minimal data — early-stage quoting |
| MQS (all-features) | Base fields plus any mqs_* application fields | Full application data available |
NAICS, state, and product are the minimum — they are not the only signals. When application data is present, the MQS model additionally consumes a broad set of firmographic and risk-eligibility datapoints, for example: legal entity type, year established (→ business age), building construction / year built (→ building age), full-time employee count, estimated annual revenue, payroll, currently-insured status, location counts, and derived ratios such as revenue and payroll per employee. Routing is automatic — the service detects mqs_* fields and selects the appropriate model with no manual configuration.
The model predicts quote likelihood (with 95% conformal confidence intervals) and likely average premium per carrier, plus plain-English explanations of why a carrier scored as it did.
The full request/response contract for the underlying prediction service is documented in the Market Intelligence API reference. The agent's ranking behavior is driven by an externalized, tenant-scoped prompt and can be tuned without a code change — see Prompt Management.
The mkt_intel event
The mkt_intel event (listed in the §8 Event Summary) fires after the MI agent writes its results. Its payload:
event: mkt_intel
data: {
"carriers_likely_to_bind": [ /* carrier objects, see below */ ],
"summary": "risk_profile:ABC Plumbing|Plumbing Contractors|OH"
}
Each carrier object:
| Field | Type | Notes |
|---|---|---|
carrier | string | Carrier display name |
subdomain | string | Carrier subdomain/identifier |
quote_likelihood | float | 0–1 (render as %, e.g. 0.85 → 85%) |
product | string | e.g. General Liability, Workers Compensation, Business Owner Property |
avg_premium | number \| null | Average premium |
avg_response_time | string \| null | Average carrier response time |
num_questions | int \| null | Carrier-specific question count |
recommended | boolean | Whether MI recommends this carrier |
rank | int \| null | Recommendation rank |
premium_trend | string \| null | Pricing direction (upward / downward / stable) |
The summary field, when present, encodes the risk profile as risk_profile:<company>|<industry>|<state>.