Skip to main content

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.

CredentialHow you obtain itHow you send it
Bearer tokenClient-credentials grant against the BP Auth API — see AuthenticateAuthorization 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,
)
info

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:

StatusReason
401Missing cookie, expired session, or invalid token
403Valid session but the run_id belongs to a different user
503Auth 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 FlowSTP Flow
TriggerBusiness name and address in messageApplication ID marker in message
Starting pointNew quote from scratchExisting application in the platform
Carrier selectionService identifies eligible carriers; broker confirmsAuto-selects best available carrier
Critique / validationawaiting_critique_review — enriched business data flagged for broker review before application is createdawaiting_naics_validation — NAICS code validated post-CQS; auto-approved unless a critical discrepancy is found
Broker gatesMore checkpoints (enrichment review, data quality, carrier confirmation, application answers, post-quote)Fewer gates — most steps are automated
Document uploadSupported (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:

StepWhat the service doesBroker gate
1. EnrichLooks up business data — NAICS, revenue, employee count, address validation
2. Critique reviewFlags enriched data issues for broker attentionawaiting_critique_review — approve or correct
3. Application creationCreates the insurance application from the enriched data
4. Carrier matchingIdentifies eligible carriers and presents them for confirmationawaiting_carrier_confirmation — confirm the list
5. Data quality checkFlags conflicting or ambiguous fields for broker resolution (if needed)awaiting_user_input — resolve or skip
6. Application questionsCollects any required fields the service could not pre-fillawaiting_application_answers — submit answers
7. Application reviewPresents the completed application for final broker sign-offawaiting_application_review — approve or correct
8. QuotingRetrieves live quotes from the confirmed carriers
9. Post-quote actionBroker takes a final action on the quotesawaiting_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: startrun_idsubagent_contentmkt_inteleligible_carriershitl_pause (awaiting_critique_review) → donecomplete

Turn 2 — Approve enriched data:

{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "approve_critique",
"payload": {}
}

Key events: startrun_idapplicationhitl_pause (awaiting_carrier_confirmation) → donecomplete

Turn 3 — Confirm carriers:

{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "confirm_application",
"payload": {}
}

Key events: startrun_idapplicationhitl_pause (awaiting_application_answers) → donecomplete

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: startrun_idquoteshitl_pause (awaiting_post_quote_actions) → donecomplete

Turn 5 — Post-quote action:

{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "bind",
"payload": {}
}

Key events: startrun_idcontentdone (pipeline_stage: null) → complete

info

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:

StepWhat the service doesBroker gate
1. Load applicationReads the existing application from the platform
2. Carrier auto-selectionSelects the best available carrier automatically — no broker confirmation required
3. CQSCollects carrier-specific questions for the selected carrierawaiting_application_answers — submit answers
4. QuotingRetrieves live quotes from the selected carrier
5. NAICS validationValidates the NAICS industry code post-CQSawaiting_naics_validation — only if a critical discrepancy is detected; auto-approved otherwise
6. Post-quote actionBroker takes a final action on the quotesawaiting_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: startrun_idapplicationeligible_carriersquoteshitl_pause (awaiting_post_quote_actions) → donecomplete

Turn 2 — Post-quote action:

{
"run_id": "20260625_005034_bb64ce44-7d88-4d85-8321-7f8edb5efd95",
"action_id": "bind",
"payload": {}
}

Key events: startrun_idcontentdone (pipeline_stage: null) → complete

Part 2 — API Reference

6. Request Schema

ChatRequest

FieldTypeRequiredDescription
messagestringNoThe broker's message. May be empty when resuming at a gate.
run_idstringNoExisting session ID to resume. Also accepted as session_id. Omit to start a new session.
resume_optionsResumeOptionsNoGate-resume parameters. See below.
action_idstringNoShorthand 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
payloadobjectNoData 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).

FieldTypeGateDescription
confirm_applicationbooleanawaiting_carrier_confirmationConfirm the presented carrier list.
critique_replystringawaiting_critique_review, awaiting_naics_validationBroker reply to data quality findings. Empty string ("") approves as-is.
application_answersobjectawaiting_application_answersMap of { question_code: answer } for unanswered questions.
review_correctionsobject[]awaiting_application_reviewList of { question_code, answer, carrier? } corrections. null means approve as-is.
correctionsobjectawaiting_user_inputField corrections for a discrepancy. E.g. {"payroll": 50000}.
proceed_without_correctionsbooleanawaiting_user_inputSkip corrections and proceed.
get_quotesbooleanawaiting_quote_selectionFetch live quote status from carriers.
add_carriersstring[]AnyAdd additional eligible carriers to the quoting pipeline.
user_idstringAnyAudit identifier for the responding user. Defaults to "user".

7. Response Headers

HeaderDescription
x-session-idSession ID for this request. Same value as run_id in the run_id event. Available before any stream event.
Content-Typetext/event-stream
Cache-Controlno-cache

8. Event Schemas

All events use the SSE wire format:

event: <name>
data: <json>

Event summary

EventWhen it firesWhat to do
startFirst event of every responseStream is open; ignore or show a loading indicator
run_idSecond event of every responseSave run_id — required to resume this session
contentWhile the assistant is replyingConcatenate and display to the broker
subagent_contentWhile the service is processingShow as a progress update
applicationAfter application data is readySnapshot of the current application
eligible_carriersAfter carrier matchingArray of carrier names eligible to quote
mkt_intelAfter carrier recommendationCarriers likely to bind, with reasoning summary
quotesAfter live quotes are fetchedQuote status and pricing from carriers
hitl_pauseAt a broker checkpointPause and prompt the broker — see below
doneLast event of every turnTurn complete; check pipeline_stage to decide next step
errorOn a terminal failureDisplay the error; start a new session
completeAfter doneStream closed; ignore

hitl_pause

Key Event

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": {}
}
FieldTypeNotes
run_idstringInclude in the resume request
pipeline_stagestringWhich checkpoint is active — see enum below
resume_hintobjectThe exact resume_options shape expected to unblock this gate
ui_componentUIComponentSpecSelf-describing UI spec for rendering the checkpoint controls

pipeline_stage values:

ValueFlowDescription
awaiting_critique_reviewQuoteBroker reviews enriched business data before application creation
awaiting_carrier_confirmationQuoteBroker confirms the list of eligible carriers
awaiting_application_answersQuoteBroker answers outstanding application questions
awaiting_user_inputQuoteBroker resolves conflicting or ambiguous data
awaiting_application_reviewQuoteBroker reviews the completed application before carrier submission
awaiting_naics_validationSTPNAICS code validated post-CQS on existing application (auto-approved unless discrepancy detected)
awaiting_quote_selectionBothBroker triggers live quote fetch from carriers
awaiting_post_quote_actionsBothBroker 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": {}
}
FieldTypeNotes
run_idstringPersist — use in every subsequent request
final_responsestringThe assistant's full text reply for this turn
pipeline_stagestring \| nullActive gate stage (see enum above), or null when the conversation is complete
ui_componentUIComponentSpecGate 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": {}
}
]
}
FieldTypeNotes
gate_typestringMatches pipeline_stage. Use this to determine which checkpoint is active. Enum values match the pipeline_stage table above.
titlestringHuman-readable heading for the checkpoint UI
descriptionstringOptional explanatory text
propsobjectCheckpoint-specific display data (carrier list, questions, etc.)
actions[].action_idstringThe 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[].labelstringDisplay label for the action button
actions[].variantstringButton style: primary, secondary, destructive
actions[].formobject[]When present: render a form; user-entered values go in payload

9. Error Codes

HTTP errors

StatusCauseAction
400Request blocked by content guardrailsSurface the detail field to the user
401Missing or expired session cookieRe-authenticate via BP Auth
403run_id belongs to a different userDo not retry with this run_id
503Auth service unreachableRetry 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)
info

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:

flowchart LR A["start"] --> B["run_id"] B --> C["content / subagent_content\napplication / mkt_intel\neligible_carriers / quotes"] C --> D["hitl_pause\n(optional)"] D --> E["done"] E --> F["complete"] style A fill:#f0fdfa,stroke:#99f6e4,color:#0d9488 style B fill:#eff6ff,stroke:#bfdbfe,color:#2563eb style C fill:#f5f3ff,stroke:#ddd6fe,color:#7c3aed style D fill:#fffbeb,stroke:#fde68a,color:#92400e style E fill:#eff6ff,stroke:#bfdbfe,color:#2563eb style F fill:#ecfdf5,stroke:#a7f3d0,color:#059669

Guarantees:

  • start is always first; complete is always last.
  • run_id always immediately follows start.
  • hitl_pause always precedes done in the same turn.
  • done always precedes complete.

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 active
  • ui_component — a self-describing specification for rendering the checkpoint UI
  • resume_hint — the exact resume_options shape 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_stageModeDescriptionaction_id options
awaiting_critique_reviewQuote FlowData quality review before application is createdapprove_critique, reply_critique
awaiting_carrier_confirmationQuote FlowConfirm carrier list before application is submittedconfirm_application
awaiting_user_inputBothResolve data discrepanciesprovide_corrections, proceed_without_corrections
awaiting_application_answersBothAnswer unanswered application questionssubmit_answers
awaiting_application_reviewBothFinal review of completed applicationapprove_application_review, submit_corrections
awaiting_naics_validationSTP FlowNAICS validation (auto-approves if no critical issue)approve_critique, reply_critique
awaiting_quote_selectionBothQuotes received; broker reviews pricingget_quotes
awaiting_post_quote_actionsBothPost-quote: bind, download, or finishbind, 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.

  1. Session starts — broker sends a message (Quote Flow or STP Flow).
  2. Enrichment and validation — the service gathers and validates business data; issues are surfaced via awaiting_critique_review if broker input is needed.
  3. Application — an application is created or the existing one is validated; checkpoints are emitted as application events.
  4. Carrier identification — eligible carriers are identified and emitted via eligible_carriers. The broker confirms (Quote Flow) or the service auto-selects (STP Flow).
  5. Application questions — any unanswered required fields are collected via awaiting_application_answers.
  6. Quoting — the service retrieves quotes from carriers; results are emitted via quotes events.
  7. 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

info

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

ConditionRecommended action
503 HTTPRetry with exponential backoff (start 1 s, cap 30 s)
error SSE eventStart a new session (omit run_id)
401 HTTPRe-authenticate and retry
403 HTTPDo not retry — wrong run_id for this user
Dropped SSE connectionReconnect immediately with the same run_id

15. Token Expiration

info

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 401 HTTP response.
  • Re-authenticate to obtain a fresh token.
  • Resume the existing session using the same run_id with 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

  1. 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.
  2. Requests market intelligence predictions for each coverage product.
  3. Cross-references the predictions against the carriers eligible to quote on the application.
  4. Persists the result to session state, which emits the mkt_intel SSE 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:

ModelInputsWhen used
Baseproduct, NAICS description, stateMinimal data — early-stage quoting
MQS (all-features)Base fields plus any mqs_* application fieldsFull 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.

tip

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:

FieldTypeNotes
carrierstringCarrier display name
subdomainstringCarrier subdomain/identifier
quote_likelihoodfloat0–1 (render as %, e.g. 0.8585%)
productstringe.g. General Liability, Workers Compensation, Business Owner Property
avg_premiumnumber \| nullAverage premium
avg_response_timestring \| nullAverage carrier response time
num_questionsint \| nullCarrier-specific question count
recommendedbooleanWhether MI recommends this carrier
rankint \| nullRecommendation rank
premium_trendstring \| nullPricing direction (upward / downward / stable)

The summary field, when present, encodes the risk profile as risk_profile:<company>|<industry>|<state>.