{"openapi":"3.1.0","info":{"title":"Hedge Submission API","version":"1.0","description":"Submit commercial insurance risks to Hedge programmatically and track\nthem to quote. One rail, two doors:\n\n- **Connected apps / broker agents**, per-user OAuth 2.1 (PKCE, dynamic\n  client registration). The broker consents once; tokens are scoped to\n  their brokerage. This is also how the Hedge MCP connector works.\n- **Systems (machine) credentials**, brokerage API clients created\n  self-serve in the broker portal (Settings → API keys) or issued by\n  Hedge ops, exchanged via the `client_credentials` grant. Submissions\n  made with a machine credential must name a `producer_email`.\n\nThe contract works like emailing Hedge a risk: **one call in, the\nsystem runs.** `POST /broker/intake` (free text and/or PDFs) or\n`POST /broker/submissions` (structured JSON) creates the submission\nand immediately starts marketing: Hedge matches appetite, sends the\nstructured clearance email to the producer listing every market being\ntried, opens the lanes, and quotes the instant-quote markets on recorded\nfavorable assumptions. Pass `hold: true` to defer the run until you call\n`finalize`. Then read `GET /broker/submissions/{id}/markets`: the markets\ncome back in three categories — **Hedge Instant Quote** (connected\ncarrier APIs), **Hedge Binding** (markets Hedge quotes for you) and\n**Hedge Specialty** (email markets) — each lane with what it still\nneeds from you, the assumptions Hedge filed on the broker's behalf\n(pre-bind attestations to confirm) and released quotes.\n`GET /broker/submissions/{id}/requirements` stays the gaps view.\n\nAll endpoints are scoped to YOUR brokerage by the token, there is no\ncross-tenant access. Base URL: `https://api.hedgespecialty.com/api/v1`.\n\n**The thread.** API brokers get the same emails an email broker gets,\nand Hedge starts the conversation (the clearance email, questions,\nquote deliveries). `GET /broker/submissions/{id}/thread` mirrors that\nconversation as one plain-text message stream (Hedge's emails, your\nreplies, and the assistant chat; never carrier correspondence), and\n`POST .../thread` replies to Hedge exactly as an email reply would:\nanswer a question, send a revision, authorize a bind. Answers arrive\nin the thread and on the `submission.message` webhook.\n\n**Webhooks (push).** Instead of polling the events feed and the\nthread, register a webhook endpoint and Hedge POSTs new submission\nevents (`submission.events`) and new thread messages\n(`submission.message`) to you as they become visible; same objects,\nsame visibility rules, minutes instead of poll intervals. Endpoints\nare managed in the broker portal (Settings → Webhooks, brokerage\nadmins only; the management API is portal-session-only by design; a\nleaked machine key must never be able to point your event stream\nsomewhere new). An endpoint's optional `event_types` filter may name\nany feed event type plus `message`. Deliveries are signed\n(svix-compatible) and documented under **Webhooks** below. Endpoints\ncreated in the staging portal receive staging deliveries, with their\nown secrets.\n\nChanges are additive-only on this version. Breaking changes ship as a\nnew version with notice to integrated partners.\n"},"externalDocs":{"description":"Hedge developer documentation","url":"https://docs.hedgespecialty.com"},"servers":[{"url":"https://api.hedgespecialty.com/api/v1","description":"Production"},{"url":"https://staging-api.hedgespecialty.com/api/v1","description":"Staging sandbox"}],"tags":[{"name":"Auth"},{"name":"Account"},{"name":"Submissions"},{"name":"Requirements"},{"name":"Carrier quotes"},{"name":"Documents"},{"name":"Policies"},{"name":"Appetite"},{"name":"Binding"},{"name":"Programs"},{"name":"Webhooks"}],"components":{"securitySchemes":{"brokerOAuth":{"type":"oauth2","description":"Broker access token. Scopes: `broker_mcp` (read), `broker_submit`\n(write). Per-user tokens come from the OAuth authorization-code +\nPKCE flow (`/oauth/authorize` → `/oauth/token`); machine tokens\nfrom `client_credentials`, using an API key created self-serve in\nthe broker portal (Settings → API keys) or issued by Hedge ops.\nAccess tokens live 60 minutes.\n","flows":{"authorizationCode":{"authorizationUrl":"https://api.hedgespecialty.com/api/v1/oauth/authorize","tokenUrl":"https://api.hedgespecialty.com/api/v1/oauth/token","scopes":{"broker_mcp":"Read brokerage-scoped submissions, policies, payments, appetite, and requirements.","broker_submit":"Create submissions, answer Hedge's asks, and act on quotes for your brokerage."}},"clientCredentials":{"tokenUrl":"https://api.hedgespecialty.com/api/v1/oauth/token","scopes":{"broker_mcp":"Read brokerage-scoped submissions, policies, payments, appetite, and requirements.","broker_submit":"Create submissions, answer Hedge's asks, and act on quotes for your brokerage."}}}}},"schemas":{"ProgramCategory":{"type":"string","enum":["instant_quote","binding","specialty"],"description":"The Hedge category of a market program, derived from how Hedge\nsubmits to it. `instant_quote` (\"Hedge Instant Quote\"): carrier API,\nHedge fills gaps with favorable assumptions and quotes in minutes;\nevery assumption is listed for the retail agent to confirm before\nbind. `binding` (\"Hedge Binding\"): carrier portal, Hedge quotes on\nyour behalf. `specialty` (\"Hedge Specialty\"): email to an\nunderwriter; completed ACORDs, program supplements and loss runs\nare needed and a human reads them, so Hedge does not assume.\n"},"Address":{"type":"object","description":"line1, city, state and zip are required together.","required":["line1","city","state","zip"],"properties":{"line1":{"type":"string"},"line2":{"type":"string"},"city":{"type":"string"},"county":{"type":"string"},"state":{"type":"string","minLength":2,"maxLength":2},"zip":{"type":"string"},"zip4":{"type":"string"},"country":{"type":"string","default":"US"}}},"Applicant":{"type":"object","required":["insured_name"],"properties":{"insured_name":{"type":"string","maxLength":256},"dba_name":{"type":"string"},"entity_type":{"type":"string","description":"Legal entity type, e.g. llc, corporation, sole_proprietor."},"fein_or_ssn":{"type":"string","description":"FEIN, or SSN for a sole proprietor."},"nature_of_business":{"type":"string"},"date_business_started":{"type":"string","format":"date"},"business_phone":{"type":"string"},"business_email":{"type":"string"},"website":{"type":"string"},"contact_first_name":{"type":"string"},"contact_last_name":{"type":"string"},"contact_title":{"type":"string","maxLength":128},"contact_phone":{"type":"string"},"contact_email":{"type":"string","description":"The producer's email. Strongly recommended: Hedge emails the\nclearance (every market being tried), any questions, and\nquotes here; the same thread an email broker gets.\n"},"naics":{"type":"string"},"sic":{"type":"string","maxLength":64},"gl_code":{"type":"string","maxLength":64},"mailing_address":{"$ref":"#/components/schemas/Address"}}},"Location":{"type":"object","required":["location_number","address"],"properties":{"location_number":{"type":"integer","minimum":1,"description":"Unique per submission."},"address":{"$ref":"#/components/schemas/Address"},"description_of_operations":{"type":"string","maxLength":10000},"employees_full_time":{"type":"integer","minimum":0},"employees_part_time":{"type":"integer","minimum":0},"annual_revenue_at_location":{"type":"number","minimum":0}}},"PriorCarrier":{"type":"object","properties":{"coverage_category":{"type":"string","description":"Canonical line slug or common alias."},"carrier_name":{"type":"string"},"policy_number":{"type":"string"},"effective_date":{"type":"string","format":"date"},"expiration_date":{"type":"string","format":"date"}}},"SubmissionCreate":{"type":"object","required":["applicant","narrative"],"properties":{"applicant":{"$ref":"#/components/schemas/Applicant"},"narrative":{"type":"string","description":"Operations description of the risk, what the business does,\nsize, anything an underwriter should know. Required; appetite\nmatching depends on it.\n"},"lines_of_business":{"type":"array","items":{"type":"string"},"description":"Canonical slugs (e.g. commercial_general_liability) or common aliases (gl, wc)."},"effective_date":{"type":"string","format":"date"},"primary_state":{"type":"string","minLength":2,"maxLength":2,"description":"Primary risk state, 2-letter US code (normalized to uppercase).\nWhen the applicant mailing address also carries a state the two\nmust agree: the request 422s on a conflict, with a message that\nsays exactly what to fix. Omit it to use the mailing address\nstate.\n"},"producer_email":{"type":"string","description":"REQUIRED when authenticating with a machine credential, the active portal user this submission is attributed to."},"insured_id":{"type":"string","format":"uuid","description":"Optional id of an existing insured from GET /broker/insureds;\nlinks the new submission to that client's account (repeat\nbusiness, a new line for an existing client). Must belong to\nyour brokerage; an unknown or foreign id returns 404.\n"},"locations":{"type":"array","maxItems":250,"items":{"$ref":"#/components/schemas/Location"},"description":"Risk locations (ACORD 125 premises). Location numbers must be unique."},"requested_coverages":{"type":"array","items":{"type":"string"},"description":"Explicit narrow coverage intent as canonical slugs (e.g.\nauto_physical_damage, motor_truck_cargo). Omit when unstated;\nan empty list means the broker explicitly selected none.\n"},"property_tiv_total":{"type":"integer","minimum":0,"description":"Total insured property value, whole dollars."},"auto_vehicle_count":{"type":"integer","minimum":0},"wc_total_annual_payroll":{"type":"integer","minimum":0,"description":"Total annual payroll, whole dollars."},"prior_carriers":{"type":"array","items":{"$ref":"#/components/schemas/PriorCarrier"},"description":"Expiring or prior carriers per line; drives loss-run requests."},"line_target_premiums":{"type":"object","additionalProperties":{"type":"integer","minimum":1},"description":"Broker-stated target annual premium per line slug, whole dollars. Non-positive values are dropped."},"structure_to_target":{"type":"boolean","default":false,"description":"Ask Hedge to structure options (limits, deductibles) to hit the target premiums."},"hold":{"type":"boolean","default":false,"description":"Defer the run. `false` (default) starts marketing as soon as the\ncreate commits — appetite match, clearance email to the\nproducer, lanes opened, instant-quote markets quoted. `true`\nholds the draft until `POST /broker/submissions/{id}/finalize`\nreleases it (attach documents and answer requirements first).\n"},"mode":{"type":"string","enum":["rater"],"description":"Partner integrations only (an acting-as partner token; anyone\nelse gets 403). `rater` quotes exactly `partner_program_ids` and\nno other market. The file is always held until `finalize`, and\n`lines_of_business` and `primary_state` are required. A live\nsubmission for the same insured returns 409 `hedge_file_exists`\nwith its `submission_id`, except your own rater submissions\n(one per coverage) where no chosen program's market already\nquotes one of its lines and no carrier application is shared.\nDifferent markets may quote the same line on sibling\nsubmissions. When your own rater submission collides, the 409\nalso lists `programs`: each colliding `program_id`, its\n`reasons` (`market_line_on_live_file`,\n`carrier_application_on_live_file`, `lines_unknown`) and the\n`submission_ids` it collides with. Untick those and retry.\n"},"partner_program_ids":{"type":"array","minItems":1,"maxItems":40,"uniqueItems":true,"items":{"type":"string","format":"uuid"},"description":"With `mode: rater` only: the exact programs to quote (API,\nportal or email programs; a portal-robot program must be\nqualified on Hedge's executor), at most one per market and\nchannel for a requested line. Each refused program is named\nwith its reasons in a 422.\n"},"partner_reference":{"type":"string","maxLength":128,"description":"With `mode: rater` only, the partner's own id for this quote\nrequest; echoed on the file's start event.\n"}}},"SubmissionCreated":{"type":"object","properties":{"submission_id":{"type":"string","format":"uuid"},"state":{"type":"string"},"status_label":{"type":"string"},"marketing_status":{"type":"string","enum":["matching","awaiting_finalization"],"description":"`matching` when the run started on create; `awaiting_finalization`\nwhen held (call `finalize` to release).\n"},"next_step":{"type":"string","description":"The call to make next, e.g. `GET /broker/submissions/{id}/markets` or `POST /broker/submissions/{id}/finalize`."},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-fatal notices about an already-created submission (e.g. a background enqueue that needs attention)."},"merged_into":{"type":"string","format":"uuid","nullable":true,"description":"Set when this create repeated a live submission for the same insured\nfrom the last day and landed on it as an update instead of opening a\nsecond file; `submission_id` is that file.\n"},"lines_added":{"type":"array","items":{"type":"string"},"description":"On a merged create from a portal session, the requested lines the\nlive file did not have, now added to it (their instant markets start\npreparing). Empty otherwise.\n"}}},"IntakeCreated":{"type":"object","description":"Result of `POST /broker/intake`.","required":["submission_id","status_label","marketing_status","next_step","applicant","portal_url"],"properties":{"submission_id":{"type":"string","format":"uuid"},"state":{"type":"string"},"status_label":{"type":"string"},"marketing_status":{"type":"string","enum":["matching","awaiting_finalization"]},"next_step":{"type":"string"},"documents":{"type":"array","description":"The originals stored on the submission, in upload order.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string"}}}},"applicant":{"type":"object","description":"What Hedge recorded for the insured — your fields, or the extractor's when you only sent text.","properties":{"insured_name":{"type":"string","nullable":true},"dba_name":{"type":"string","nullable":true},"entity_type":{"type":"string","nullable":true},"business_phone":{"type":"string","nullable":true},"business_email":{"type":"string","nullable":true},"website":{"type":"string","nullable":true},"naics":{"type":"string","nullable":true},"nature_of_business":{"type":"string","nullable":true},"contact_first_name":{"type":"string","nullable":true},"contact_last_name":{"type":"string","nullable":true},"contact_email":{"type":"string","nullable":true},"contact_phone":{"type":"string","nullable":true},"mailing_address":{"type":"object","nullable":true,"properties":{"line1":{"type":"string"},"line2":{"type":"string","nullable":true},"city":{"type":"string"},"state":{"type":"string"},"zip":{"type":"string"}}}}},"warnings":{"type":"array","items":{"type":"string"},"description":"Non-fatal notices (a file that was not stored, a background enqueue that needs attention, a replayed request)."},"portal_url":{"type":"string","format":"uri"}}},"LaneAssumption":{"type":"object","description":"One favorable default a carrier adapter filed on the broker's behalf\nto obtain an instant quote. Every assumption is a pre-bind\nattestation the producer must confirm; `confirmed` is `false` while\nit still stands on the carrier session and `true` once the broker's\nconfirmation retired it.\n","required":["key","label","confirmed"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"nullable":true},"confirmed":{"type":"boolean"}}},"LaneQuote":{"type":"object","description":"A released, firm quote on the lane (indications never appear here).","required":["quote_id","premium_cents","total_cents","premium"],"properties":{"quote_id":{"type":"string","format":"uuid"},"premium_cents":{"type":"integer","deprecated":true,"description":"Equals `total_cents` (the all-in total, not the bare premium). Use `total_cents`, or `GET /broker/submissions/{id}/quotes` for the itemized split."},"total_cents":{"type":"integer","description":"The quote's all-in total (premium + taxes + fees), in cents."},"premium":{"type":"string","example":"$8,559"},"lines":{"type":"array","items":{"type":"string"}},"is_revision":{"type":"boolean","description":"Present only when this quote supersedes an earlier released price."}}},"Lane":{"type":"object","required":["lane_id","program_category","status","status_label","submit_ready","bound"],"properties":{"lane_id":{"type":"string","format":"uuid"},"market_id":{"type":"string","format":"uuid","nullable":true},"market_name":{"type":"string","nullable":true},"program":{"type":"string","nullable":true},"program_id":{"type":"string","format":"uuid","nullable":true},"program_category":{"$ref":"#/components/schemas/ProgramCategory"},"lines":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"status_label":{"type":"string"},"submit_ready":{"type":"boolean"},"needs_from_you":{"type":"array","items":{"type":"string"},"description":"Broker-actionable asks, present only while the lane is gapped."},"assumptions":{"type":"array","items":{"$ref":"#/components/schemas/LaneAssumption"}},"quotes":{"type":"array","items":{"$ref":"#/components/schemas/LaneQuote"}},"bound":{"type":"boolean"}}},"MarketCategoryGroup":{"type":"object","required":["category","label","description","lanes"],"properties":{"category":{"$ref":"#/components/schemas/ProgramCategory"},"label":{"type":"string","description":"Hedge Instant Quote, Hedge Binding, or Hedge Specialty."},"description":{"type":"string"},"lanes":{"type":"array","items":{"$ref":"#/components/schemas/Lane"}}}},"SubmissionMarkets":{"type":"object","required":["submission_id","generated_at","categories"],"properties":{"submission_id":{"type":"string","format":"uuid"},"generated_at":{"type":"string","format":"date-time"},"categories":{"type":"array","description":"Always all three categories, in order instant_quote, binding, specialty — empty ones included.","items":{"$ref":"#/components/schemas/MarketCategoryGroup"}}}},"SpeedHint":{"type":"object","description":"A channel-level expectation (`basis` is `channel_default`), never a per-program promise.","required":["hint","label","basis"],"properties":{"hint":{"type":"string","enum":["minutes","within_day","underwriter_review"]},"label":{"type":"string","example":"Usually within minutes"},"basis":{"type":"string","enum":["channel_default"]}}},"QuoteDocument":{"type":"object","description":"`download_path` is an authenticated Hedge route (call it with the same\ntoken) that serves a carrier PDF Hedge stored; `carrier_url` is a\ncarrier-hosted https link.\n","properties":{"kind":{"type":"string","nullable":true,"example":"quote_pdf"},"file_name":{"type":"string","nullable":true},"download_path":{"type":"string","nullable":true},"carrier_url":{"type":"string","nullable":true}}},"ItemizedQuote":{"type":"object","description":"One released firm quote, itemized. All money is integer cents with\n`pricing.currency` `USD`; `null` means unknown and never means zero.\nPrices are null when `presentation.checkout_ready` is false, exactly\nas the Hedge proposal withholds them. The surplus-lines tax split is\nfilled only when Hedge's pricing ledger agrees with the stored totals\n(`pricing.breakdown_reconciled`); otherwise only the tax total shows.\n","required":["quote_id","lane_id","kind","carrier","admitted","presentation","pricing","bind"],"properties":{"quote_id":{"type":"string","format":"uuid"},"lane_id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["firm"]},"is_revision":{"type":"boolean","nullable":true,"description":"Null while revision marking is off."},"revision_of_quote_id":{"type":"string","format":"uuid","nullable":true},"created_at":{"type":"string","format":"date-time","nullable":true},"carrier":{"type":"object","properties":{"display_name":{"type":"string","nullable":true},"logo_url":{"type":"string","nullable":true},"mga_name":{"type":"string","nullable":true}}},"issuing_company":{"type":"object","nullable":true,"properties":{"legal_name":{"type":"string","nullable":true},"naic":{"type":"string","nullable":true},"am_best_rating":{"type":"string","nullable":true}}},"admitted":{"type":"string","enum":["admitted","non_admitted","unknown"]},"program_name":{"type":"string","nullable":true},"quote_number":{"type":"string","nullable":true},"lines":{"type":"array","items":{"type":"string"}},"effective_date":{"type":"string","format":"date","nullable":true},"expiration_date":{"type":"string","format":"date","nullable":true},"quote_expires_on":{"type":"string","format":"date","nullable":true},"presentation":{"type":"object","properties":{"mode":{"type":"string","enum":["full_summary","source_only"]},"financial_status":{"type":"string"},"terms_status":{"type":"string"},"checkout_ready":{"type":"boolean"}}},"pricing":{"type":"object","properties":{"currency":{"type":"string","enum":["USD"]},"basis":{"type":"string","enum":["term"]},"premium_cents":{"type":"integer","nullable":true},"taxes":{"type":"object","properties":{"total_cents":{"type":"integer","nullable":true},"surplus_lines_tax_cents":{"type":"integer","nullable":true},"stamping_fee_cents":{"type":"integer","nullable":true},"other_cents":{"type":"integer","nullable":true},"computed_by":{"type":"string","nullable":true,"enum":["inscipher",null]}}},"fees":{"type":"object","properties":{"total_cents":{"type":"integer","nullable":true},"carrier_fees_cents":{"type":"integer","nullable":true},"hedge_broker_fee_cents":{"type":"integer","nullable":true}}},"total_cents":{"type":"integer","nullable":true},"breakdown_reconciled":{"type":"boolean"},"payment_options":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","enum":["in_full","monthly"]},"total_cents":{"type":"integer","nullable":true},"down_payment_cents":{"type":"integer","nullable":true},"installment_cents":{"type":"integer","nullable":true},"installments":{"type":"integer","nullable":true},"disclaimer":{"type":"string","nullable":true}}}}}},"coverages":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","nullable":true},"label":{"type":"string","nullable":true},"limit_text":{"type":"string","nullable":true},"deductible_text":{"type":"string","nullable":true},"note":{"type":"string","nullable":true}}}},"primary_limit_cents":{"type":"integer","nullable":true,"description":"Strict parse of the first coverage row's limit; null when absent or ambiguous."},"primary_deductible_cents":{"type":"integer","nullable":true},"endorsements":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","nullable":true},"name":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"limit":{"type":"string","nullable":true}}}},"subjectivities":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string"},"prompt":{"type":"string"},"optional":{"type":"boolean"},"due_stage":{"type":"string","nullable":true,"example":"pre_bind"},"status":{"type":"string","nullable":true,"example":"open"}}}},"notes":{"type":"array","items":{"type":"string"}},"compliance_notices":{"type":"object","nullable":true},"documents":{"type":"array","items":{"$ref":"#/components/schemas/QuoteDocument"}},"bind":{"type":"object","properties":{"available":{"type":"boolean"},"blocked_reason":{"type":"string","nullable":true,"enum":["bound","bind_in_progress","line_bound_elsewhere","closed_at_carrier","not_bindable","incomplete_terms","expired",null],"description":"`bound` / `bind_in_progress`: this lane is bound or has a live\nbind request. `line_bound_elsewhere`: the same coverage line is\nbound or binding on another lane. `closed_at_carrier`: the\ncarrier closed this quote. `not_bindable`: not bindable terms\n(for example awaiting carrier approval). `incomplete_terms`:\nnot checkout-ready (prices are withheld). `expired`: past\n`quote_expires_on`.\n"}}}}},"QuoteLane":{"type":"object","required":["lane_id","market","status","status_label"],"properties":{"lane_id":{"type":"string","format":"uuid"},"program_id":{"type":"string","format":"uuid","nullable":true},"program_name":{"type":"string","nullable":true},"program_category":{"$ref":"#/components/schemas/ProgramCategory"},"channel":{"type":"string","nullable":true,"enum":["api","portal","email",null]},"market":{"type":"object","properties":{"id":{"type":"string","format":"uuid","nullable":true},"slug":{"type":"string","nullable":true},"display_name":{"type":"string","nullable":true},"logo_url":{"type":"string","nullable":true}}},"lines":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["bound","binding","quoted","declined","blocked","no_quote","needs_info","indicated","pending"],"description":"First match wins: `bound` (the carrier bound it; `status_label`\nreads \"Bound, policy documents pending\" until its policy is\nissued), `binding` (a live bind\nrequest), `quoted` (at least one quote in `quotes`), `declined`,\n`blocked` (another broker holds the account at this market),\n`no_quote` (withdrawn, or the submission closed), `needs_info`,\n`indicated` (a non-binding indication only; never priced here),\n`pending`.\n"},"status_label":{"type":"string"},"status_reason":{"type":"object","nullable":true,"properties":{"code":{"type":"string"},"text":{"type":"string","nullable":true}}},"speed":{"$ref":"#/components/schemas/SpeedHint"},"needs_from_you":{"type":"array","items":{"type":"string"}},"assumptions":{"type":"array","items":{"$ref":"#/components/schemas/LaneAssumption"}},"carrier_originals":{"type":"array","description":"Carrier original offers whose terms Hedge is still confirming.","items":{"$ref":"#/components/schemas/QuoteDocument"}},"quotes":{"type":"array","items":{"$ref":"#/components/schemas/ItemizedQuote"}}}},"SubmissionQuotes":{"type":"object","required":["submission_id","generated_at","revision","lanes"],"properties":{"submission_id":{"type":"string","format":"uuid"},"generated_at":{"type":"string","format":"date-time"},"revision":{"type":"string","description":"Changes whenever anything in `lanes` changes."},"lanes":{"type":"array","items":{"$ref":"#/components/schemas/QuoteLane"}}}},"SharedQuestion":{"type":"object","required":["id","key","label","help","type","options","required","show_if","section","assumed_default","prefill_from"],"properties":{"id":{"type":"string","description":"The program's own answer path, stable within the set (an object's parts are `<object>.<part>`)."},"key":{"type":"string","description":"Shared answer key: Hedge's fact key when the question means that fact in the same form, else `program.<program_slug>.<id>`."},"label":{"type":"string"},"help":{"type":"string","nullable":true},"type":{"type":"string","enum":["text","textarea","number","currency","percent","integer","boolean","select","multiselect","date","state","address","list"],"description":"`list`: the answer is a JSON array; rows shaped by `item_questions`, or plain text values when `item_questions` is absent."},"options":{"type":"array","description":"Choices for select / multiselect (empty otherwise). Send `value` unchanged; it may be a string, number or boolean.","items":{"type":"object","required":["value","label"],"properties":{"value":{},"label":{"type":"string"}}}},"required":{"type":"boolean","description":"Required whenever the question is shown."},"show_if":{"type":"array","items":{"$ref":"#/components/schemas/SharedQuestionCondition"}},"required_if":{"type":"array","items":{"$ref":"#/components/schemas/SharedQuestionCondition"},"description":"When present, the question is required only while these conditions hold."},"one_of_group":{"type":"string","description":"An answer to any question in the same group satisfies the group."},"section":{"type":"string","nullable":true},"assumed_default":{"nullable":true,"description":"The answer Hedge would assume when unanswered, when one is fixed in advance; null otherwise (Hedge then decides from the file at quote time)."},"prefill_from":{"type":"string","nullable":true},"item_questions":{"type":"array","items":{"$ref":"#/components/schemas/SharedQuestion"},"description":"For a `list`: each row's questions. Keys are `<list key>.<id>`; a row condition on a sibling uses the sibling's key."}}},"CatalogQuery":{"type":"object","additionalProperties":false,"required":["lines","state"],"properties":{"lines":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"string","example":"commercial_general_liability"},"description":"Hedge line slugs; `businessowners` expands to general liability plus property. Unknown values return 422 `unknown_line`."},"state":{"type":"string","minLength":2,"maxLength":2,"description":"Primary risk state."},"exposure_states":{"type":"array","maxItems":60,"items":{"type":"string"},"description":"Every location state; each must pass the market and program state checks."},"naics":{"type":"string","pattern":"^\\d{2,6}$","nullable":true},"annual_revenue_cents":{"type":"integer","minimum":0,"nullable":true,"description":"Optional. Missing revenue is a warning (`revenue_unknown`)","never an exclusion.":null},"effective_date":{"type":"string","format":"date","nullable":true},"all_channels":{"type":"boolean","default":false,"description":"`false` (default): connected carrier APIs and the portals Hedge\ndrives, with one default per market, channel and line. `true`:\nevery channel, adding manual-portal (`channel: portal`) and email\n(`channel: email`) programs, an `appetite` status on each row, and\nHedge's pre-checks for the `hedge` group (at most 8 per line).\n"}}},"CatalogAppetite":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["fit","review","excluded"],"description":"`fit`: Hedge would send it (API and portal programs on line of\nbusiness; email programs whose published appetite matches the\nNAICS class). `review`: passes every line, state, class and\nbrokerage check, and Hedge reviews appetite before sending (the\nusual email case). `excluded`: a check fails (rows in `excluded`\nonly).\n"},"reason":{"type":"string","nullable":true,"description":"Plain-English reason to show when present."}}},"CatalogResult":{"type":"object","required":["catalog_version","generated_at","scope","programs","excluded"],"properties":{"catalog_version":{"type":"string"},"generated_at":{"type":"string","format":"date-time"},"scope":{"type":"object","properties":{"lines":{"type":"array","items":{"type":"string"}},"state":{"type":"string"},"exposure_states":{"type":"array","items":{"type":"string"}},"naics":{"type":"string","nullable":true},"brokerage_scoped":{"type":"boolean"},"all_channels":{"type":"boolean"}}},"programs":{"type":"array","items":{"type":"object","properties":{"program_id":{"type":"string","format":"uuid"},"program_name":{"type":"string"},"market":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string","nullable":true},"display_name":{"type":"string"},"logo_url":{"type":"string","nullable":true}}},"issuing_company":{"type":"object","nullable":true,"properties":{"legal_name":{"type":"string","nullable":true},"naic":{"type":"string","nullable":true},"admitted":{"type":"boolean","nullable":true},"am_best_rating":{"type":"string","nullable":true}}},"channel":{"type":"string","enum":["api","portal","email"],"description":"`email` only with `all_channels`. `portal` covers the portals Hedge drives and, with `all_channels`, manual portals."},"group":{"type":"string","enum":["instant","hedge"],"description":"`instant` for `api`; `hedge` for `portal` and `email`."},"route_label":{"type":"string","enum":["Instant quote","Hedge Binding","Hedge Specialty"],"description":"Small-print route name for `api`, `portal` and `email` respectively."},"appetite":{"$ref":"#/components/schemas/CatalogAppetite"},"lines":{"type":"array","items":{"type":"string"}},"default_selected":{"type":"boolean"},"default_lines":{"type":"array","items":{"type":"string"},"description":"The lines this program is the default for. Pre-select each\ndefault program with exactly these lines (one program per\nmarket, channel and line). With `all_channels`, `hedge` rows\nare pre-selected only when `fit` and among Hedge's top picks\nfor the line (at most 8 per line, ranked by Hedge's market\nresults); `instant` rows keep one default per market and line.\n"},"alternative_of":{"type":"string","format":"uuid","nullable":true,"description":"The sibling Hedge sends instead at the same market, channel and line; null for that primary program, pre-selected or not."},"speed":{"$ref":"#/components/schemas/SpeedHint"},"fit":{"type":"string","enum":["line_match"]},"warnings":{"type":"array","items":{"type":"string"}},"bind_path":{"type":"string","enum":["hedge_portal"]}}}},"excluded":{"type":"array","items":{"type":"object","properties":{"program_id":{"type":"string","format":"uuid"},"program_name":{"type":"string"},"market":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"display_name":{"type":"string"}}},"channel":{"type":"string","enum":["api","portal","email"]},"group":{"type":"string","enum":["instant","hedge"]},"route_label":{"type":"string","enum":["Instant quote","Hedge Binding","Hedge Specialty"]},"appetite":{"$ref":"#/components/schemas/CatalogAppetite"},"lines":{"type":"array","items":{"type":"string"}},"reasons":{"type":"array","items":{"type":"string"},"example":["broker_program_excluded"]}}}}}},"Requirements":{"type":"object","description":"The live \"what's still needed\" view.","properties":{"submission_id":{"type":"string","format":"uuid"},"insured_name":{"type":"string"},"lines":{"type":"array","items":{"type":"string"}},"effective_date":{"type":"string","format":"date"},"state":{"type":"string"},"forms":{"type":"array","items":{"type":"string"},"description":"Application forms Hedge prepares for this risk (ACORD baseline + recommended carrier supplements)."},"marketing_status":{"type":"string","enum":["not_started","matching","matched","no_markets_matched"],"description":"Where the asynchronous marketing pipeline is. Matching runs for\na few minutes after `finalize`, so an empty `markets` list means\n\"still matching\" when this is `matching`; not \"no appetite\".\n"},"marketing_hint":{"type":"string","nullable":true,"description":"Human-readable next step for the current marketing_status."},"form_fill_active":{"type":"boolean","description":"A live form-fill session owns the form set."},"markets":{"type":"array","description":"Per-market readiness (deterministic, no model on this read).","items":{"type":"object","properties":{"market_name":{"type":"string"},"ready":{"type":"boolean"},"needs_from_you":{"type":"array","items":{"type":"string"},"description":"Items only you can supply."},"hedge_obtains":{"type":"array","items":{"type":"string"},"description":"Items Hedge fetches itself; informational."},"lane_id":{"type":"string","format":"uuid","nullable":true,"description":"The market lane this row belongs to (same id as rail.lanes[].submission_market_id)."},"program":{"type":"string","nullable":true},"program_category":{"$ref":"#/components/schemas/ProgramCategory"},"category_label":{"type":"string","nullable":true,"example":"Hedge Instant Quote"}}}},"carrier_api_sessions":{"type":"array","description":"Instant-quote (carrier API) sessions and their open question gaps.","items":{"type":"object","properties":{"session_id":{"type":"string","format":"uuid"},"carrier_slug":{"type":"string"},"program":{"type":"string"},"status":{"type":"string"},"outcome":{"type":"string","nullable":true},"completion_pct":{"type":"number"},"missing_questions":{"type":"array","items":{"type":"object"}},"has_quote":{"type":"boolean"}}}},"documents_on_file":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"kind_label":{"type":"string"},"display_name":{"type":"string"}}}},"assessment":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/RequirementsAssessment"}],"description":"The canonical per-program requirements assessment (null if that section failed to build)."},"rail":{"nullable":true,"allOf":[{"$ref":"#/components/schemas/MarketRail"}],"description":"The per-lane market rail, the same block the broker portal shows (null if that section failed to build)."}}},"RequirementsAssessment":{"type":"object","description":"Every matched program with what it needs. `gapped` lists lanes an\nenforcing program is holding for a broker-supplied item;\n`submitted_or_ready` lists lanes that are ready or already sent.\nPrograms with `enforcement: report_only` list `unmet` items but\nare NOT held; never render them as waiting on you.\n","properties":{"submission_id":{"type":"string","format":"uuid"},"generated_at":{"type":"string","format":"date-time"},"submitted_or_ready":{"type":"array","items":{"type":"string","format":"uuid"}},"gapped":{"type":"array","items":{"type":"string","format":"uuid"}},"programs":{"type":"array","items":{"type":"object","properties":{"submission_market_id":{"type":"string","format":"uuid"},"market_name":{"type":"string","nullable":true},"program_id":{"type":"string","format":"uuid","nullable":true},"program_display_name":{"type":"string","nullable":true},"channel":{"type":"string","nullable":true,"enum":["email","api","portal",null]},"program_category":{"$ref":"#/components/schemas/ProgramCategory"},"enforcement":{"type":"string","enum":["enforce","report_only","none"]},"submit_ready":{"type":"boolean"},"met":{"type":"array","items":{"$ref":"#/components/schemas/AssessedRequirement"}},"unmet":{"type":"array","items":{"$ref":"#/components/schemas/AssessedRequirement"}},"deferred":{"type":"array","items":{"$ref":"#/components/schemas/AssessedRequirement"}},"evaluated_at":{"type":"string","format":"date-time"}}}}}},"AssessedRequirement":{"type":"object","properties":{"key":{"type":"string","nullable":true},"label":{"type":"string"},"severity":{"type":"string","description":"hard or preferred"},"resolution":{"type":"string","description":"broker (you supply), auto (Hedge fetches) or internal"},"repr":{"type":"string","description":"structured, free_text, form or file"},"form_key":{"type":"string","nullable":true},"due_stage":{"type":"string","description":"quote or bind"},"satisfied":{"type":"boolean","nullable":true},"blocks_submission":{"type":"boolean","nullable":true}}},"MarketRail":{"type":"object","properties":{"generated_at":{"type":"string","format":"date-time"},"lanes":{"type":"array","items":{"$ref":"#/components/schemas/RailLane"}},"quote_history":{"type":"array","description":"Expired or invalidated quotes, for context.","items":{"type":"object","properties":{"history_key":{"type":"string"},"market_name":{"type":"string"},"program":{"type":"string","nullable":true},"outcome":{"type":"string","enum":["expired","invalid"]},"observed_at":{"type":"string","format":"date-time"},"next_step":{"type":"string","nullable":true}}}},"quote_history_unavailable":{"type":"boolean"}}},"RailLane":{"type":"object","description":"One market lane on this submission, in the shape the broker portal renders.","properties":{"submission_market_id":{"type":"string","format":"uuid","description":"The lane id used across this API (lane_id elsewhere)."},"market_id":{"type":"string","format":"uuid","nullable":true},"market_name":{"type":"string","nullable":true},"program":{"type":"string","nullable":true},"program_id":{"type":"string","format":"uuid","nullable":true},"program_category":{"$ref":"#/components/schemas/ProgramCategory"},"lines":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"status_label":{"type":"string"},"submit_ready":{"type":"boolean"},"gapped":{"type":"boolean","description":"Held for something only you can supply (see `unmet_labels`)."},"unmet_labels":{"type":"array","items":{"type":"string"}},"quotes":{"type":"array","items":{"type":"object","properties":{"quote_id":{"type":"string","format":"uuid"},"premium_display":{"type":"string"},"total_cents":{"type":"integer"},"lines":{"type":"array","items":{"type":"string"}},"is_revision":{"type":"boolean","nullable":true}}}},"source_offers":{"type":"array","description":"Carrier-original quote or indication documents.","items":{"type":"object","properties":{"presentation_id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["quote","indication"]},"label":{"type":"string"},"document_url":{"type":"string"},"filename":{"type":"string","nullable":true}}}},"bound":{"type":"boolean"},"chip":{"type":"string","enum":["bound","quoted","not_available","needs_info","in_progress"]},"carrier_api_session_ids":{"type":"array","nullable":true,"items":{"type":"string","format":"uuid"}}}},"BindAssumption":{"type":"object","description":"One assumption Hedge made to obtain the quote (a value it defaulted\non the carrier application because the file did not state it) that\nthe retail agent has not yet confirmed. `key` is what\n`attest_assumptions` lists; `label` is the plain-language statement;\n`value` is the exact value asserted to the carrier (absent when the\nentry records none).\n","required":["key","label"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"value":{"description":"The asserted value","any JSON type; may be absent.":null}}},"BindRequestCreate":{"type":"object","required":["quote_id"],"properties":{"quote_id":{"type":"string","format":"uuid","description":"The released firm quote to bind: the `quote_id` shown on this\nsubmission's rail lanes / markets rows. Indications cannot be\nbound (422).\n"},"payment_option":{"type":"string","enum":["in_full","monthly"],"default":"in_full","description":"The payment plan requested on the bind order."},"attest_assumptions":{"description":"`false` (default) confirms nothing. `true` confirms EVERY\nstanding assumption on the quote's carrier application (the set\n`unconfirmed_assumptions` lists). A list of keys confirms only\nthose keys; keys matching no standing assumption are ignored,\nnever invented. Send `true`/keys only after the retail agent has\nreviewed each statement: the confirmation is recorded on the bind\nrequest's timeline under the producing broker (the same record\nthe QB writes for a broker's written confirmation). It is a\nrecorded consent, not a hold, and it is the ONLY bind check.\n","oneOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"default":false},"producer_email":{"type":"string","description":"REQUIRED with a machine credential; the active portal user this bind is attributed to (`requested_by`). Ignored for per-user tokens."}}},"BindRequestSubmit":{"type":"object","properties":{"attest_assumptions":{"description":"Same semantics as on create; lets the caller confirm at submit time.","oneOf":[{"type":"boolean"},{"type":"array","items":{"type":"string"}}],"default":false},"producer_email":{"type":"string","description":"REQUIRED with a machine credential."}}},"BindContingency":{"type":"object","description":"One pre-bind item the carrier needs, with your response state.","required":["id","kind","label","status","required"],"properties":{"id":{"type":"string","format":"uuid"},"kind":{"type":"string","enum":["question","signed_form","loss_runs","file_upload"]},"label":{"type":"string","description":"The carrier's wording of the item."},"status":{"type":"string","enum":["pending","satisfied","waived"]},"required":{"type":"boolean"},"upload_path":{"type":"string","nullable":true,"description":"While the request is `drafted`, the path to POST a PDF for this item (multipart `file`); null afterwards."},"esign_status":{"type":"string","nullable":true,"description":"Envelope state of a signature request started for this item through the Hedge portal wizard (e.g. sent, completed, queued_for_review); null when none."}}},"BindRequestRead":{"type":"object","required":["bind_request_id","submission_id","status","status_label","requested_at","unconfirmed_assumptions","contingencies","next_steps"],"properties":{"bind_request_id":{"type":"string","format":"uuid"},"submission_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["drafted","submitted","sent","binder_received","bound","bind_failed","cancelled","declined","expired"],"description":"`drafted`: checklist open (upload documents, confirm assumptions,\nthen submit). `submitted`/`sent`: Hedge is placing the bind with\nthe carrier. `binder_received`: the carrier confirmed the bind;\ncoverage is bound and its policy documents are pending.\n`bound`: the policy is issued (it appears under GET\n/broker/policies and a `bound` event is emitted). `bind_failed`:\nHedge is reviewing.\n"},"status_label":{"type":"string"},"quote_id":{"type":"string","format":"uuid","nullable":true},"payment_option":{"type":"string","nullable":true},"requested_at":{"type":"string","format":"date-time"},"requested_by":{"type":"string","nullable":true,"description":"The producing broker the request is attributed to."},"effective_date":{"type":"string","format":"date","nullable":true},"policy_id":{"type":"string","format":"uuid","nullable":true},"unconfirmed_assumptions":{"type":"array","items":{"$ref":"#/components/schemas/BindAssumption"},"description":"Standing assumptions the retail agent still has to confirm. Non-empty means create/submit will answer 409 `assumptions_unconfirmed` until attested."},"contingencies":{"type":"array","items":{"$ref":"#/components/schemas/BindContingency"}},"next_steps":{"type":"array","items":{"type":"string"},"description":"Plain-language actions for the current state, in order."}}},"BindAssumptionsUnconfirmed":{"type":"object","description":"409 body from create/submit. The bind request exists as a draft\n(`bind_request_id`); re-POST the create (idempotent for the same\nquote) or POST submit with `attest_assumptions` to confirm.\n","required":["code","message","bind_request_id","assumptions"],"properties":{"code":{"type":"string","const":"assumptions_unconfirmed"},"message":{"type":"string"},"bind_request_id":{"type":"string","format":"uuid"},"assumptions":{"type":"array","items":{"$ref":"#/components/schemas/BindAssumption"}}}},"Program":{"type":"object","required":["program_id","market_id","market_name","name","lines","enabled","application_schema_available"],"properties":{"program_id":{"type":"string","format":"uuid"},"market_id":{"type":"string","format":"uuid"},"market_name":{"type":"string"},"name":{"type":"string"},"program_category":{"type":"string","nullable":true,"enum":["instant_quote","binding","specialty"],"description":"`instant_quote`: quoted live through a carrier API; your own\napplication can plug in via the program's application-schema.\n`binding`: Hedge quotes it for you. `specialty`: completed\nACORDs, program requirements and loss runs are required.\n"},"category_label":{"type":"string","nullable":true},"lines":{"type":"array","items":{"type":"string"},"description":"Canonical line-of-business slugs."},"states":{"type":"array","nullable":true,"items":{"type":"string"},"description":"2-letter state codes where the program is available; null means no state restriction."},"description":{"type":"string","nullable":true},"enabled":{"type":"boolean","description":"Your brokerage's own on/off preference (see GET /broker/market-access)."},"application_schema_available":{"type":"boolean","description":"True when Hedge holds a cached question schema for this program (filed after Hedge's first quote with it), so GET /broker/programs/{program_id}/application-schema will serve it."}}},"ProgramQuestion":{"type":"object","required":["key","label","type","required","repeatable"],"properties":{"key":{"type":"string","description":"Stable answer key; use it as the answer key in application checkpoints."},"label":{"type":"string"},"type":{"type":"string","description":"Normalized field type (e.g. text, number, boolean, select, multiselect, date, group, collection)."},"required":{"type":"boolean"},"options":{"type":"array","nullable":true,"items":{"type":"object","properties":{"value":{},"label":{"type":"string"}}}},"help":{"type":"string","nullable":true},"depends_on":{"type":"array","nullable":true,"items":{"type":"string"},"description":"Keys of other questions whose answers decide whether this one applies."},"required_when":{"type":"object","nullable":true,"description":"Conditional requiredness when declared: {field, op (equals|not_equals|in|not_in|truthy|falsy), value}."},"one_of_group":{"type":"string","nullable":true},"repeatable":{"type":"boolean","description":"True for collections (answer is a list of items shaped by `questions`)."},"questions":{"type":"array","nullable":true,"items":{"$ref":"#/components/schemas/ProgramQuestion"},"description":"Nested questions for group / collection items."}}},"ProgramApplicationSchema":{"type":"object","required":["program_id","market_id","name","program_category","contract_version","schema_fingerprint","sections"],"properties":{"program_id":{"type":"string","format":"uuid"},"market_id":{"type":"string","format":"uuid"},"name":{"type":"string"},"program_category":{"type":"string","const":"instant_quote"},"contract_version":{"type":"string","const":"structured_v1"},"schema_fingerprint":{"type":"string","description":"Content hash of the served schema; changes when the carrier's questions change. Per-application fingerprints for checkpoints come from the application-workspace."},"title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"sections":{"type":"array","items":{"type":"object","required":["key","label","questions"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"questions":{"type":"array","items":{"$ref":"#/components/schemas/ProgramQuestion"}}}}}}},"SharedQuestionCondition":{"type":"object","required":["key","op","value"],"description":"One condition on another question's answer, found by that\nquestion's `key`. Conditions in a list are ANDed. Semantics: `eq`\nand `in` compare type and value exactly; `ne` / `not_in` are false\nfor an unanswered question; `truthy` is true unless the answer is\nnull, false, 0, \"\" or an empty list or object; `falsy` is exactly\nfalse, 0 or \"\" (an unanswered question is not falsy); `gt` /\n`gte` / `lt` / `lte` compare numbers; `exists` is whether the\nquestion is answered. `any_of` / `all_of` group `conditions` (then\n`key` is null). `any_item`: the answer is a list and one item must\nsatisfy `op` / `value`. A condition whose `key` no question carries\nrefers to a fact Hedge sets itself; treat it as unanswered.\n","properties":{"key":{"type":"string","nullable":true},"op":{"type":"string","enum":["eq","ne","in","not_in","truthy","falsy","gt","gte","lt","lte","exists","any_of","all_of"]},"value":{"description":"Comparison value (JSON)","null for truthy / falsy / groups.":null},"any_item":{"type":"boolean"},"reference":{"type":"object","description":"A keyed-row lookup Hedge evaluates natively."},"conditions":{"type":"array","items":{"$ref":"#/components/schemas/SharedQuestionCondition"}}}},"SourceReference":{"type":"object","description":"Provenance of a fact or answer.","required":["source_id","content_hash","channel"],"properties":{"source_id":{"type":"string"},"content_hash":{"type":"string"},"channel":{"type":"string","enum":["broker_portal","broker_email","insured","connected_app","document","paste","mapping"]},"evidence":{"type":"string","enum":["explicit","translated","assumed"],"default":"explicit"},"snippet":{"type":"string","nullable":true},"extractor_version":{"type":"string","nullable":true}}},"Fact":{"type":"object","required":["key","value","source"],"properties":{"key":{"type":"string"},"value":{},"scope":{"type":"string","default":"insured"},"period":{"type":"string","nullable":true},"source":{"$ref":"#/components/schemas/SourceReference"},"confirmed":{"type":"boolean","default":false}}},"FactEnvelope":{"type":"object","description":"The submission's shared facts (the Brief) as the applications see them; one revision counter for the whole set.","required":["contract_version","workspace_id","fact_set_id","owner_host","owner_resource_id","revision","facts"],"properties":{"contract_version":{"type":"string","const":"structured_v1"},"workspace_id":{"type":"string"},"fact_set_id":{"type":"string"},"owner_host":{"type":"string","enum":["hedge","bindly"]},"owner_resource_id":{"type":"string"},"revision":{"type":"integer"},"replica_applied_revision":{"type":"integer"},"facts":{"type":"array","items":{"$ref":"#/components/schemas/Fact"}}}},"ApplicationSection":{"type":"object","description":"One carrier application (a carrier-API quote session) inside the\nworkspace: its schema, current answers, per-field ownership, and\nreadiness. `application_id` is the `session_id` used by the\ncheckpoint / request-quote / employers-classes paths. Revisions\n(`answer_revision`, `fact_revision`, `selection_revision`) and\n`schema_fingerprint` are the optimistic-concurrency tokens every\ncommand must echo.\n","required":["application_id","workspace_id","provider_key","program_identifier","schema","schema_fingerprint","answers","answer_revision","readiness","request_state"],"properties":{"application_id":{"type":"string"},"workspace_id":{"type":"string"},"connection_id":{"type":"string"},"provider_key":{"type":"string"},"program_identifier":{"type":"string"},"owner_host":{"type":"string","enum":["hedge","bindly"]},"owner_session_id":{"type":"string"},"route":{"type":"string","enum":["hedge","direct"]},"market_program_id":{"type":"string","format":"uuid","nullable":true},"submission_id":{"type":"string","format":"uuid","nullable":true},"line_of_business":{"type":"string","nullable":true},"schema":{"type":"object","description":"The normalized question schema (fields, required_field_keys, program identity); the same questions GET /broker/programs/{program_id}/application-schema projects."},"schema_fingerprint":{"type":"string"},"answers":{"type":"object","additionalProperties":true,"description":"Current answers keyed by question key."},"ownership":{"type":"object","additionalProperties":{"type":"object","properties":{"kind":{"type":"string","enum":["explicit","derived","cleared"]},"revision":{"type":"integer"},"source":{"$ref":"#/components/schemas/SourceReference"},"dependencies":{"type":"array","items":{"type":"string"}}}}},"answer_revision":{"type":"integer"},"fact_revision":{"type":"integer"},"selection_revision":{"type":"integer"},"selected_products":{"type":"array","items":{"type":"string"}},"available_products":{"type":"array","items":{"type":"string"}},"mapping_state":{"type":"string","description":"Whether Hedge's fact-to-answer mapping is idle or still running for this application."},"unresolved_dependencies":{"type":"array","items":{"type":"string"}},"missing":{"type":"array","items":{"type":"string"},"description":"Required question keys still unanswered."},"errors":{"type":"array","items":{"type":"object","additionalProperties":{"type":"string"}}},"visible_fields":{"type":"array","items":{"type":"string"}},"readiness":{"type":"string","description":"`needs_information` until every required visible question is answered, then `ready_for_quote`."},"request_state":{"type":"string","description":"Lifecycle of the last quote request for this application (draft until one is made)."},"request_id":{"type":"string","nullable":true},"result":{"type":"object","nullable":true,"additionalProperties":true,"description":"The carrier outcome of the last request","when any.":null},"allowed_actions":{"type":"array","items":{"type":"string"}}}},"ApplicationWorkspace":{"type":"object","description":"The consolidated per-submission application surface: the shared\nfacts plus one `ApplicationSection` per active carrier application.\nSubmissions not on the structured application workflow return\n`workflow_version: legacy` with an empty `applications` list.\n","required":["workspace_id","workflow_version","applications"],"properties":{"contract_version":{"type":"string","const":"structured_v1"},"workspace_id":{"type":"string"},"workflow_version":{"type":"string","description":"`structured_v1`, or `legacy` when this submission does not use the workspace."},"facts":{"$ref":"#/components/schemas/FactEnvelope"},"applications":{"type":"array","items":{"$ref":"#/components/schemas/ApplicationSection"}},"residual_pdf":{"type":"object","additionalProperties":true,"description":"State of any residual PDF forms Hedge still prepares outside the carrier applications (`status`, `form_keys`)."}}},"CheckpointCommand":{"type":"object","description":"Save answers to one application. Optimistic concurrency: echo the\napplication's current `answer_revision` and `schema_fingerprint`; a\nmismatch answers 409 with the current application so you can\nre-apply. `operation_id` makes the save idempotent: a retried\ncommand with the same id replays the original receipt.\n","required":["operation_id","expected_answer_revision","expected_schema_fingerprint"],"properties":{"operation_id":{"type":"string"},"expected_answer_revision":{"type":"integer"},"expected_schema_fingerprint":{"type":"string"},"field_changes":{"type":"object","additionalProperties":true,"description":"Answers to set","keyed by question key.":null},"explicit_clears":{"type":"array","items":{"type":"string"},"description":"Question keys to clear explicitly."},"collection_operations":{"type":"array","items":{"type":"object","required":["field_key","operation","record_id"],"properties":{"field_key":{"type":"string"},"operation":{"type":"string","enum":["insert","update","remove"]},"record_id":{"type":"string"},"changes":{"type":"object","additionalProperties":true}}}},"selected_products":{"type":"array","nullable":true,"items":{"type":"string"}},"source_reference":{"$ref":"#/components/schemas/SourceReference"}}},"CheckpointReceipt":{"type":"object","required":["operation_id","application","applied","rejected"],"properties":{"operation_id":{"type":"string"},"application":{"$ref":"#/components/schemas/ApplicationSection"},"applied":{"type":"array","items":{"type":"string"}},"rejected":{"type":"array","items":{"type":"object","additionalProperties":{"type":"string"}}},"fact_changes":{"type":"array","items":{"$ref":"#/components/schemas/Fact"}},"facts_status":{"type":"string"}}},"QuoteCommand":{"type":"object","description":"Request a quote for one application; every revision token must match the application you reviewed (409 otherwise).","required":["operation_id","expected_answer_revision","expected_schema_fingerprint","expected_fact_revision","expected_selection_revision"],"properties":{"operation_id":{"type":"string"},"expected_answer_revision":{"type":"integer"},"expected_schema_fingerprint":{"type":"string"},"expected_fact_revision":{"type":"integer"},"expected_selection_revision":{"type":"integer"}}},"ThreadMessage":{"type":"object","description":"One broker-facing message on a submission, normalized across\nchannels. `direction` is relative to Hedge: `inbound` = your\nbrokerage wrote it (an email reply, or a message sent through\n`POST .../thread` or the portal assistant), `outbound` = Hedge\nwrote it. `channel` is `email` for emails Hedge exchanged with\nyour brokerage and `chat` for assistant-chat rows; `from`/`to`\nare email addresses and are null/empty on chat rows.\n","required":["id","channel","direction","kind","occurred_at","body_text"],"properties":{"id":{"type":"string","format":"uuid"},"channel":{"type":"string","enum":["email","chat"]},"direction":{"type":"string","enum":["inbound","outbound"]},"kind":{"type":"string","description":"The email's type (e.g. initial_clearance, market_plan_update, quote_delivery, broker_reply) or `chat`."},"occurred_at":{"type":"string","format":"date-time"},"subject":{"type":"string","nullable":true},"body_text":{"type":"string","description":"Plain text. HTML-only emails are converted server-side."},"from":{"type":"string","nullable":true},"to":{"type":"array","items":{"type":"string"}},"attachments":{"type":"array","items":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"download_path":{"type":"string","nullable":true,"description":"Present when the file is a finalized document you can fetch via `GET /broker/finalized-documents/{document_id}/pdf` (relative to the base URL)."}}}},"in_reply_to":{"type":"string","nullable":true,"description":"RFC 5322 Message-ID this email replied to, when known."},"delivered_via":{"type":"string","enum":["email","partner"],"nullable":true,"description":"How a Hedge-written message reached you. `partner` means it was delivered to a partner app's thread (for example Hedge Connector) instead of being emailed. Null for your own messages and chat rows."}}},"ThreadPage":{"type":"object","properties":{"messages":{"type":"array","items":{"$ref":"#/components/schemas/ThreadMessage"}},"next_cursor":{"type":"string","nullable":true}}},"ThreadReply":{"type":"object","required":["body"],"properties":{"body":{"type":"string","minLength":1,"maxLength":20000,"description":"Your reply to Hedge, plain text. Written exactly as you would reply to Hedge's email."},"document_ids":{"type":"array","maxItems":10,"items":{"type":"string","format":"uuid"},"description":"Ids of documents you already uploaded to this submission (`POST .../documents`) to attach to the reply. Every id must belong to this submission (400 otherwise)."},"producer_email":{"type":"string","description":"REQUIRED when authenticating with a machine credential; the active portal user this reply is attributed to."}}},"ThreadReplyAccepted":{"type":"object","required":["message_id","status","detail"],"properties":{"message_id":{"type":"string","format":"uuid","description":"The thread id of your message (readable via `GET .../thread`)."},"status":{"type":"string","const":"received"},"detail":{"type":"string"}}}}},"security":[{"brokerOAuth":[]}],"paths":{"/oauth/register":{"post":{"tags":["Auth"],"operationId":"registerOAuthClient","summary":"Register an OAuth client (Dynamic Client Registration)","security":[],"description":"RFC 7591. Public PKCE clients only; no client_secret is ever issued\nhere. Returns a stateless signed client_id you use on /oauth/authorize\nand /oauth/device_authorization. Machine (client_credentials)\ncredentials are not issued by this endpoint: create them self-serve\nin the broker portal (Settings → API keys) or ask Hedge ops.\n","responses":{"201":{"description":"Client registration ({client_id, client_name, redirect_uris})"},"400":{"description":"Invalid registration request"}}}},"/oauth/authorize":{"get":{"tags":["Auth"],"operationId":"startOAuthAuthorization","summary":"Start the browser authorization flow","security":[],"description":"RFC 6749 authorization endpoint, PKCE (S256) required. Redirects the\nbroker to the portal consent screen; on approval the browser returns\nto your redirect_uri with a single-use code for /oauth/token. Use the\ndevice flow instead for headless or CLI contexts.\n","responses":{"302":{"description":"Redirect to the consent screen"},"400":{"description":"Unknown client or invalid redirect_uri"}}}},"/oauth/device_authorization":{"post":{"tags":["Auth"],"operationId":"startOAuthDeviceAuthorization","summary":"Start the device authorization flow","security":[],"description":"RFC 8628. Form-encoded client_id (+ optional scope). Returns a\ndevice_code to poll /oauth/token with\n(grant_type=urn:ietf:params:oauth:grant-type:device_code), plus a\nuser_code and verification_uri the broker opens to approve. Codes\nexpire after 15 minutes; poll no faster than the returned interval.\n","responses":{"200":{"description":"Device authorization ({device_code, user_code, verification_uri, verification_uri_complete, expires_in, interval})"},"400":{"description":"Unknown client"}}}},"/oauth/token":{"post":{"tags":["Auth"],"operationId":"exchangeOAuthToken","summary":"Exchange credentials for an access token","security":[],"description":"`grant_type=authorization_code` (+ PKCE) and `grant_type=refresh_token`\nfor per-user connections; `grant_type=client_credentials` with your\n`client_id` + `client_secret` for machine credentials. Form-encoded.\n","responses":{"200":{"description":"Token response ({access_token, token_type, expires_in, scope})"},"400":{"description":"Invalid request or grant"},"401":{"description":"Invalid credentials"}}}},"/broker/me":{"get":{"tags":["Account"],"operationId":"getBrokerIdentity","summary":"Who am I (user or machine credential)","description":"Returns the authenticated identity plus the brokerage. Two shapes,\ndiscriminated by `kind`:\n\n- `kind: user` (portal session or per-user OAuth token): `id`,\n  `email`, `full_name`, `role`, `brokerage`, `active_states`.\n- `kind: api_client` (machine credential): `client_id` (the public\n  `bac_...` identifier), `label`, `scope` (the token's granted\n  scopes), `brokerage`, `active_states`.\n\n`active_states` lists the US states Hedge is currently active in;\n`null` means no gating (all states).\n","responses":{"200":{"description":"Identity (user shape or api_client shape)"},"401":{"description":"Account or credential is no longer active"}}}},"/broker/submissions":{"get":{"tags":["Submissions"],"operationId":"listSubmissions","summary":"List your brokerage's submissions","description":"Newest first. All filters are optional; a bare call returns the full\nbook. Each row carries `origin`: null for a normal Hedge submission,\nor `{partner, label, mode}` when an API partner (Hedge Connector)\ncreated it. Files a partner is still quoting in its own app\n(`mode: rater`) are not listed until the agency binds through Hedge;\nthey stay readable by id.\n","parameters":[{"in":"query","name":"status","schema":{"type":"string","enum":["intake","preparing","marketing","quoting","binding","bound","issued","lost","cancelled"]},"description":"Exact submission state. Unknown values return 422 with the valid list."},{"in":"query","name":"search","schema":{"type":"string","maxLength":256},"description":"Case-insensitive match on the insured name (literal, wildcards are escaped)."},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":500},"description":"Max rows to return. Unbounded when omitted."},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip, for paging with limit."},{"in":"query","name":"updated_since","schema":{"type":"string","format":"date-time"},"description":"Only submissions updated at or after this timestamp (delta sync)."}],"responses":{"200":{"description":"Submission list"},"422":{"description":"Invalid filter (e.g. limit over 500)"}}},"post":{"tags":["Submissions"],"operationId":"createSubmission","summary":"Create a submission","description":"Creates the submission and starts the run: appetite match, the\nstructured clearance email to the producer, lanes opened, the\ninstant-quote markets quoted on recorded favorable assumptions.\nDocuments uploaded afterwards flow into the open lanes. Pass\n`hold: true` to defer the run until `finalize`; an\n`expected_document_sha256s` manifest also holds (you declared\noriginals are still coming).\n\nThe response's `marketing_status` says which happened (`matching` or\n`awaiting_finalization`) and `next_step` names the call to make.\n\nSupports an `Idempotency-Key` header: a retried create with the same\nkey within 24h replays the original response instead of creating a\nduplicate. A concurrent duplicate returns 409, retry shortly.\n","parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string"},"required":false}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionCreated"}}}},"409":{"description":"Same Idempotency-Key already in flight"},"422":{"description":"Validation error (message says exactly what to fix)"},"429":{"description":"Daily create limit reached"}}}},"/broker/intake":{"post":{"tags":["Submissions"],"operationId":"intakeSubmission","summary":"Send Hedge a risk the way you would email it (text and/or PDFs)","description":"One multipart call in, the system runs. Send free text (an email\nbody, notes, an ACORD summary), PDFs (ACORDs, loss runs,\nsupplements), or both. When `insured_name` is omitted Hedge reads\nthe insured, contact, address, website, NAICS, phone and email out\nof `text`. Files are validated up front, stored on the new\nsubmission and extracted into its brief in the background — this\ncall never waits on extraction. Then, unless `hold` is set, Hedge\nstarts marketing exactly as `POST /broker/submissions` does.\n\nRequires `text` or `insured_name` (422 otherwise). Machine\ncredentials must name `producer_email`. Supports an\n`Idempotency-Key` header keyed on your raw inputs, so a retried\ncall replays the saved submission (with its documents) instead of\ncreating a duplicate. Counts toward the daily create and upload\nlimits.\n","parameters":[{"in":"header","name":"Idempotency-Key","schema":{"type":"string"},"required":false}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"text":{"type":"string","description":"The risk as you would describe it in an email. Required unless insured_name is given."},"files":{"type":"array","description":"Up to 20 PDFs (ACORDs, loss runs, supplements), 15 MB each.","items":{"type":"string","format":"binary"}},"insured_name":{"type":"string"},"effective_date":{"type":"string","format":"date"},"lines_of_business":{"type":"string","description":"Comma-separated canonical slugs or common aliases (e.g. `gl,property`)."},"primary_state":{"type":"string","minLength":2,"maxLength":2,"description":"Primary risk state, 2-letter US code."},"producer_email":{"type":"string","description":"REQUIRED when authenticating with a machine credential; the active portal user this submission is attributed to."},"hold":{"type":"boolean","default":false,"description":"Defer the run until `finalize`."}}}}}},"responses":{"201":{"description":"Created; the run started unless held.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntakeCreated"}}}},"400":{"description":"A file is not a valid PDF/document"},"409":{"description":"Same Idempotency-Key already in flight","or reused with different inputs":null},"413":{"description":"A file is over the 15 MB limit"},"415":{"description":"Unsupported document type"},"422":{"description":"Neither text nor insured_name; missing producer_email for a machine credential; the insured could not be identified from text; invalid date","state or line of business":null},"429":{"description":"Daily create limit reached"},"503":{"description":"Text extraction is temporarily unavailable; your text is preserved","retry":null}}}},"/broker/submissions/{submission_id}/markets":{"get":{"tags":["Requirements"],"operationId":"getSubmissionMarkets","summary":"The markets being tried, in three categories, with asks, assumptions and quotes","description":"The live picture of the run, grouped the way the clearance email\nlists it: **Hedge Instant Quote** (`instant_quote`, connected\ncarrier APIs quoted on recorded favorable assumptions), **Hedge\nBinding** (`binding`, markets Hedge quotes for you) and **Hedge\nSpecialty** (`specialty`, email markets that need completed ACORDs,\nprogram requirements and loss runs). All three categories are always\npresent, in that order, even when empty.\n\nEach lane carries its status, `submit_ready`, `needs_from_you` (the\nbroker-actionable asks, only while the lane is gapped),\n`assumptions` (each a pre-bind attestation the producer must\nconfirm; `confirmed: false` means still standing) and released\n`quotes`. Deterministic and read-only; poll it after create —\nmatching usually lands within about 5 minutes, and an empty view\nduring `matching` is not \"no appetite\".\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The three market categories","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionMarkets"}}}},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/quotes":{"get":{"tags":["Carrier quotes"],"operationId":"getSubmissionQuotes","summary":"Every released quote on a submission, itemized, with each lane's status","description":"The quote set is exactly what you see in the Hedge portal: released\nfirm quotes only (indications and quotes whose terms Hedge is still\nconfirming never appear as quotes). Each quote carries premium,\ntaxes (with the surplus-lines split when it reconciles), fees,\ntotal and payment options in integer cents with `currency: USD`,\nplus coverages, subjectivities (with `due_stage` and `status`),\nissuing company, admitted status, dates, documents and whether it\ncan be bound now. Each lane carries its status (see `QuoteLane`),\nthe assumptions Hedge recorded, and carrier original offers.\n\n`null` means unknown, never zero. Deterministic and read-only; poll\nit, or re-read it after a webhook. `revision` changes whenever the\nlanes change. A partner acting for your brokerage reads only the\nsubmissions that partner created; others return 404 to it.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The lanes and their released quotes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubmissionQuotes"}}}},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/partner-bind-links":{"post":{"tags":["Binding"],"operationId":"createPartnerBindLink","summary":"Mint a one-time bind link (partner integrations only)","description":"For an API partner acting for your brokerage (a token carrying the\npartner claim, with `broker_submit`) on a submission that partner\ncreated. Returns a one-time Hedge portal sign-in URL for\n`producer_email` that opens this quote: `landing` is `bind` (the bind\nchecklist), `quote` (terms still incomplete, or the quote binds on\nthe carrier's own portal) or `status` (the lane is binding or bound).\nThe URL expires after about 120 seconds and works once. It is a\ncredential: redirect the signed-in user to it immediately and never\nstore, email or log it. The first redemption makes the partner's\nfile a normal Hedge file.\n\n`producer_email` must be an active portal user of your brokerage, or\na producer on file with your brokerage (Hedge then creates their\nportal account; no email is sent). `return_url` must be https on an\norigin Hedge approved for the partner; the portal offers it as the\nway back. Any other caller, or a submission the partner did not\ncreate, gets 404.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["quote_id","producer_email","return_url","consent"],"additionalProperties":false,"properties":{"quote_id":{"type":"string","format":"uuid","description":"A quote from GET .../quotes."},"producer_email":{"type":"string","maxLength":255},"return_url":{"type":"string","maxLength":2048},"consent":{"type":"object","required":["statement_version","accepted_at"],"additionalProperties":false,"properties":{"statement_version":{"type":"string","maxLength":128},"accepted_at":{"type":"string","format":"date-time","description":"Must carry a UTC offset."}}}}}}}},"responses":{"201":{"description":"The link (the response carries `Cache-Control: no-store`)","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"landing":{"type":"string","enum":["bind","quote","status"]}}}}}},"403":{"description":"Missing broker_submit scope","or a staff impersonation session":null},"404":{"description":"Not a partner token","not the partner's submission":null,"or not your brokerage's":null},"409":{"description":"`quote_not_available`, `quote_expired`, `quote_not_bindable` (with `reason`), `brokerage_portal_disabled` or `producer_email_conflict`"},"422":{"description":"`return_url_not_allowed`, `producer_not_provisioned`, or a body validation error"},"429":{"description":"Rate limited (60 links a minute per partner","10 an hour per quote)":null},"503":{"description":"`proposal_unavailable`: try again shortly"}}}},"/broker/submissions/{submission_id}":{"get":{"tags":["Submissions"],"operationId":"getSubmission","summary":"Get one submission (status, markets, documents)","description":"The submission header (id, insured_name, lines, state, status_label,\npremium, primary_state, effective_date, created_at, updated_at) plus\nthe live marketing roll-up:\n\n- `markets`: one entry per engaged carrier with per-line rows\n  (line, status, status_label, quote premium in cents and dollars,\n  last update, decline/withdrawal notes).\n- `status_summary`: counts by status and per-line quoted/total\n  progress.\n- `documents`: finalized documents on file, each with a\n  `download_path` you can GET with the same bearer token.\n- `bor_actions`: Broker of Record workstreams, empty for most\n  submissions.\n- `origin`: null, or `{partner, label, mode}` when an API partner\n  (Hedge Connector) created the submission; `mode` is `rater` while\n  the partner is quoting it and `normal` after.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Submission detail with marketing roll-up"},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/events":{"get":{"tags":["Submissions"],"operationId":"listSubmissionEvents","summary":"Poll a submission's market events (quotes, declines, progress)","description":"The change feed for one submission; poll it to surface outcomes\nthat arrive hours after submit on email/portal markets (a carrier\nquoting back, declining, or a market being engaged) without diffing\nthe detail view. Events are ordered oldest-first with a stable\ncursor.\n\n**The end-of-stream signal is the cursor, never page length.** A\nnon-null `next_cursor` means more events may exist: store it and\npoll again with `since=next_cursor` until you receive a null. A\npage may hold fewer than `limit` events; or none at all; with a\nnon-null cursor (internal audit rows are scanned but never\nreturned, and a bounded per-request scan can stop early); never\ntreat a short page as the tail. `next_cursor` is null only when\nthe request proved your position is the tail of the\ncurrently-visible stream; resume later polls from your last\nnon-null cursor. Event ids are stable, so re-reading an older\ncursor is always safe (dedupe by `id`).\n\n`type` is a closed set:\n\n- `market_attached`; a market was engaged (sent to underwriter).\n- `quote_received`; a quote was received and relayed to you (the\n  quote itself is on the submission detail / proposal).\n- `status_changed`; other movement, e.g. quote in progress or a\n  market re-engaged.\n- `declined`, `withdrawn`, `blocked`; terminal outcomes for a\n  market; `detail` carries the recorded rationale when there is one.\n- `bound`; coverage placed with that market.\n\nEach event: `{id, type, occurred_at, market: {name, lines,\nlane_id, category}, status, status_label, detail?}`. `category`\nis the market's Hedge category (instant_quote, binding,\nspecialty) and `lane_id` matches `rail.lanes[].submission_market_id`. `status`/`status_label` use the\nsame vocabulary as the submission detail's `markets` roll-up.\nEvents reflect what is currently visible to your brokerage; the\nsame rules as the detail view (markets Hedge has actually engaged;\nquotes only once relayed).\n\nBecause visibility is evaluated at read time while the cursor is a\nposition over the underlying log, a market that becomes visible\nlater (e.g. its quote gets relayed after your cursor passed its\nearly rows) can enter your stream mid-history; a `quote_received`\nwithout a preceding `market_attached`. Treat each event as\nself-contained rather than assuming lifecycle completeness, and\nread `GET /broker/submissions/{submission_id}` for authoritative\ncurrent state. Re-reading from an older (or empty) cursor replays\nthe full currently-visible history when you need to backfill.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"since","schema":{"type":"string"},"description":"Opaque cursor from a previous page's next_cursor; returns events strictly after it. Omit to read from the beginning."},{"in":"query","name":"limit","schema":{"type":"integer","default":50},"description":"Max events per page (internal audit rows are not counted). Values outside [1, 100] are clamped, never rejected."}],"responses":{"200":{"description":"One page of events plus the follow-up cursor","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["market_attached","quote_received","status_changed","declined","withdrawn","blocked","bound"]},"occurred_at":{"type":"string","format":"date-time"},"market":{"type":"object","properties":{"name":{"type":"string"},"lines":{"type":"array","items":{"type":"string"}},"lane_id":{"type":"string","format":"uuid","nullable":true,"description":"The market lane (same id as rail.lanes[].submission_market_id)."},"category":{"$ref":"#/components/schemas/ProgramCategory"}}},"status":{"type":"string"},"status_label":{"type":"string"},"detail":{"type":"string","nullable":true}}}},"next_cursor":{"type":"string","nullable":true}}}}}},"404":{"description":"Not found (or not your brokerage's)"},"422":{"description":"Invalid since cursor"}}}},"/broker/submissions/{submission_id}/thread":{"get":{"tags":["Submissions"],"operationId":"getSubmissionThread","summary":"Read the conversation with Hedge on a submission","description":"Everything Hedge has said to your brokerage about this submission\nand everything your brokerage said back, oldest first: the\nclearance email, questions, market-plan updates, quote deliveries,\nyour email replies, and messages exchanged with the assistant\n(through the portal or `POST .../thread`). Each item is a\n`ThreadMessage`; `body_text` is always plain text. Carrier and\ninsured correspondence is never included.\n\n**The end-of-stream signal is the cursor, never page length.** A\nnon-null `next_cursor` means more messages may exist: store it and\npoll again with `since=next_cursor` until you receive a null.\n`next_cursor` is null only when the request proved your position\nis the tail. Message ids are stable, so re-reading an older cursor\nis always safe (dedupe by `id`). Prefer the `submission.message`\nwebhook for push delivery of the same objects.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"since","schema":{"type":"string"},"description":"Opaque cursor from a previous page's next_cursor; returns messages strictly after it. Omit to read from the beginning."},{"in":"query","name":"limit","schema":{"type":"integer","default":50},"description":"Max messages per page. Values outside [1, 200] are clamped, never rejected."}],"responses":{"200":{"description":"One page of messages plus the follow-up cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadPage"}}}},"404":{"description":"Not found (or not your brokerage's)"},"422":{"description":"Invalid since cursor"}}},"post":{"tags":["Submissions"],"operationId":"replyToSubmissionThread","summary":"Reply to Hedge on a submission (answer, revise, authorize a bind)","description":"Identical in effect to replying to Hedge's email. Use it to answer\na question Hedge asked, send a revision, attach documents you\nalready uploaded, or give a bind authorization (\"bind the Kinsale\nquote, effective 10/1\"). Your message is recorded on the thread\nand Hedge's quarterback answers on the same submission; the answer\narrives in the thread and on the `submission.message` webhook,\ntypically within a couple of minutes. Requires the `broker_submit`\nscope. Machine credentials must name `producer_email`.\n\nSend an `Idempotency-Key` header (up to 128 characters, unique per\nmessage) so a retried request attaches to the same turn instead of\nsending your message twice.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"header","name":"Idempotency-Key","required":false,"schema":{"type":"string","maxLength":128},"description":"Client-generated key; a retry with the same key replays or attaches to the original turn."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadReply"}}}},"responses":{"202":{"description":"Received; Hedge is answering asynchronously.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ThreadReplyAccepted"}}}},"400":{"description":"A document id does not belong to this submission","or the message could not be started":null},"403":{"description":"Token lacks the broker_submit scope"},"404":{"description":"Not found (or not your brokerage's)"},"422":{"description":"Blank body","body over 20000 characters":null,"missing/unknown producer_email for a machine credential":null,"or Idempotency-Key too long":null}}}},"/broker/submissions/{submission_id}/documents":{"post":{"tags":["Submissions"],"operationId":"uploadSubmissionDocument","summary":"Attach a PDF (ACORD, loss runs, supplement)","description":"Multipart upload, PDF only, 15 MB max per file. Uploaded applications are auto-extracted into the submission brief.","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"201":{"description":"Stored"},"400":{"description":"Not a valid PDF"},"413":{"description":"PDF is over the 15 MB limit. Split the package or compress the PDF."},"429":{"description":"Daily upload limit reached"}}}},"/broker/forms":{"get":{"tags":["Requirements"],"operationId":"listBlankApplicationForms","summary":"Search the blank application-form catalog","description":"ACORD baseline plus Hedge/carrier supplemental applications; the\nsame form keys the requirements view lists under `forms`. `q`\nmatches key or title (case-insensitive); results cap at 50.\n","parameters":[{"in":"query","name":"q","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Matching forms","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"form_key":{"type":"string","example":"HEDGE_15_LIQUOR_LIABILITY_SUPPLEMENTAL"},"title":{"type":"string"},"is_acord":{"type":"boolean"},"page_count":{"type":"integer"}}}}}}}}}},"/broker/forms/supplementals.zip":{"get":{"tags":["Requirements"],"operationId":"downloadAllHedgeSupplementals","summary":"Download all blank Hedge supplemental applications","description":"Returns a ZIP of the original fillable Hedge application PDFs.","responses":{"200":{"description":"All blank Hedge supplementals","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"No supplemental forms available"}}}},"/broker/forms/{form_key}/pdf":{"get":{"tags":["Requirements"],"operationId":"downloadBlankApplicationForm","summary":"Download a blank application form","description":"Serves the editable AcroForm blank; fill it in any PDF editor and attach it to the submission.","parameters":[{"in":"path","name":"form_key","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The blank PDF"},"404":{"description":"Unknown form key"}}}},"/broker/submissions/{submission_id}/finalized-documents":{"get":{"tags":["Documents"],"operationId":"listSubmissionDocuments","summary":"List a submission's documents","description":"Finalized documents on file for one of your submissions: rendered\nACORDs, supplements, your own uploads, received documents. Each row\ncarries `id`, `source`, `source_label`, `display_name`, `size_bytes`,\n`content_type`, `created_at` and a `download_path` for the PDF route\nbelow. Proposal-surface documents (carrier quote PDFs, bind-wizard\nuploads) are excluded.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Document list (empty for a submission that is not yours)"}}}},"/broker/finalized-documents/{document_id}/pdf":{"get":{"tags":["Documents"],"operationId":"downloadSubmissionDocument","summary":"Download a submission document PDF","description":"Streams the PDF, brokerage-scoped. Form fields stay editable; widget appearances are baked so filled values render in any viewer.","parameters":[{"in":"path","name":"document_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The PDF bytes","content":{"application/pdf":{}}},"404":{"description":"Not found (or not your brokerage's)"},"502":{"description":"Stored document could not be retrieved"}}}},"/broker/submissions/{submission_id}/source-offers/{presentation_id}/original":{"get":{"tags":["Documents"],"operationId":"downloadCarrierOriginalOffer","summary":"Download a carrier's original quote or indication document","description":"Streams the carrier-original PDF referenced by `rail.lanes[].source_offers[].presentation_id`, brokerage-scoped.","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"presentation_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The PDF bytes","content":{"application/pdf":{}}},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/requirements":{"get":{"tags":["Requirements"],"operationId":"getSubmissionRequirements","summary":"What this submission still needs","description":"The contract centerpiece, per-market readiness (`needs_from_you` =\nitems only you can supply), live carrier question gaps, the resolved\nform set, and documents already on file. Deterministic and fast; poll\nit between uploads/answers and finalize.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Requirements view","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Requirements"}}}}}}},"/broker/submissions/{submission_id}/market-rail":{"get":{"tags":["Requirements"],"operationId":"getSubmissionMarketRail","summary":"The market rail alone (cheap poll)","description":"The per-lane block from the requirements view without its heavier\nsections; zero writes, safe to poll every few seconds while you\nwatch a submission. `GET .../requirements` carries the same block\nunder `rail`.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Market rail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketRail"}}}},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/appetite-preview":{"get":{"tags":["Appetite"],"operationId":"getSubmissionAppetitePreview","summary":"Markets Hedge expects to approach for a draft","description":"Deterministic preview (no model) of the in-appetite markets for a\nsubmission's lines, classification and state, filtered by your\nbrokerage's market visibility. Informational; marketing never waits on it.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"{markets: [{market_id, name, program, program_category, lines: [...]}], excluded_market_ids: [...]}"},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/market-exclusions":{"put":{"tags":["Appetite"],"operationId":"setSubmissionMarketExclusions","summary":"Replace the set of markets to skip for this submission","description":"Idempotent full replacement of the market ids Hedge must not\napproach for this submission. Live instant-quote sessions with an\nexcluded market are withdrawn. Requires `broker_submit`.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["excluded_market_ids"],"properties":{"excluded_market_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}}},"responses":{"200":{"description":"What persisted: {excluded_market_ids, withdrawn_sessions}"},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/form-fill-session":{"post":{"tags":["Requirements"],"operationId":"startFormFillSession","summary":"Start an assisted application interview (Bindly form filler)","description":"Spawns the embedded form-filler session that walks the insured or\nproducer through the application forms Hedge resolved for the risk\n(ACORD baseline plus recommended supplements). Returns a token\nbridge you embed or link to; the completed forms land on the\nsubmission as finalized documents. Required forms are always kept\neven when `form_keys` trims the set. Requires `broker_submit`.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"form_keys":{"type":"array","items":{"type":"string"},"description":"Optional trim of the resolved form set (see `GET /broker/forms`)."}}}}}},"responses":{"200":{"description":"{session_id, workflow_version, token, auth_mode, forms_assigned, status, carrier_schemas}"},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/api-quotes/sessions":{"get":{"tags":["Carrier quotes"],"operationId":"listCarrierQuoteSessions","summary":"List carrier-API quote sessions and their question gaps","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Sessions with missing_required_questions_json"}}}},"/broker/submissions/{submission_id}/api-quotes/sessions/{session_id}/answers":{"post":{"tags":["Carrier quotes"],"operationId":"saveCarrierAnswers","summary":"Answer a carrier session's questions (merge-write)","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"session_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Refreshed session with remaining gaps"}}}},"/broker/submissions/{submission_id}/api-quotes/sessions/{session_id}/close":{"post":{"tags":["Carrier quotes"],"operationId":"requestCarrierQuote","summary":"Request indication then quote","description":"Soft-fails, if the carrier still needs answers, the returned session's outcome is awaiting_answers with the gaps listed.","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"session_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Session with quote (quote_json","quote_pdf_url) or remaining gaps":null}}}},"/broker/submissions/{submission_id}/application-workspace":{"get":{"tags":["Carrier quotes"],"operationId":"getApplicationWorkspace","summary":"The consolidated application workspace for a submission","description":"One read for everything an external application builder needs on a\nsubmission: the shared facts (`facts`) and one `ApplicationSection`\nper active carrier application — its question schema (the same\nquestions as the program's application-schema), current answers,\nper-field ownership, `missing` required keys, `readiness`, the last\nquote request state and result, and the revision tokens every write\nmust echo. Submissions not on the structured workflow return\n`workflow_version: legacy` with no applications. Read scope is\nenough.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApplicationWorkspace"}}}},"404":{"description":"Submission not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/application-workspace/changes":{"get":{"tags":["Carrier quotes"],"operationId":"streamApplicationWorkspaceChanges","summary":"Server-sent events when the workspace changes","description":"`text/event-stream`. Emits `connected` once with the current change\ncursor, then `changed` (data `{submission_id, cursor}`) whenever any\napplication or the shared facts change (a checkpoint, a mapping\npass, a carrier result), with comment heartbeats between. The\nstream lives at most 60 seconds or until the token expires —\nreconnect to keep listening. On `changed`, re-read the workspace.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Event stream","content":{"text/event-stream":{"schema":{"type":"string"}}}},"404":{"description":"Submission not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/application-workspace/quote-products":{"put":{"tags":["Carrier quotes"],"operationId":"setApplicationQuoteProducts","summary":"Choose which programs to quote (portal session only)","description":"Selects the programs (products) whose applications should be quoted\nfor this submission. Portal-session only by design — a connected app\nor machine token answers 403; use the Hedge portal to change product\nselection. `expected_revision` is the workspace's selection revision.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["program_ids","selected_ids","expected_revision"],"properties":{"program_ids":{"type":"array","items":{"type":"string","format":"uuid"},"minItems":1,"maxItems":100},"selected_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":100},"expected_revision":{"type":"integer","minimum":0}}}}}},"responses":{"200":{"description":"The refreshed selection"},"403":{"description":"Requires an unrestricted broker portal session"},"404":{"description":"Submission not found (or not your brokerage's)"},"409":{"description":"Selection revision is stale"}}}},"/broker/submissions/{submission_id}/applications/{session_id}":{"get":{"tags":["Carrier quotes"],"operationId":"getApplication","summary":"One carrier application from the workspace","description":"One carrier application, presented exactly as the\napplication-workspace read presents it, so a client can refresh a\nsingle application after a `changed` event. `session_id` is the\n`ApplicationSection.application_id`. 404 with `code: read_workspace`\nmeans read the whole workspace instead: the application is a Hedge\nor legacy application, its session was withdrawn, or it is outside\nthe selected quoting scope. Read scope is enough.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"session_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The application","content":{"application/json":{"schema":{"type":"object","required":["application"],"properties":{"application":{"$ref":"#/components/schemas/ApplicationSection"}}}}}},"404":{"description":"Submission not found (or not your brokerage's), or `code: read_workspace`"}}}},"/broker/submissions/{submission_id}/applications/{session_id}/checkpoint":{"post":{"tags":["Carrier quotes"],"operationId":"checkpointApplication","summary":"Save answers to one carrier application","description":"The write half of the workspace. `session_id` is the\n`ApplicationSection.application_id`. Send answers keyed by the\nprogram's question keys in `field_changes` (clears in\n`explicit_clears`, list edits in `collection_operations`) together\nwith the application's current `answer_revision` and\n`schema_fingerprint`. Idempotent per `operation_id`. Returns a\nreceipt with the refreshed application, the keys applied and\nrejected, and any shared-fact changes the answers implied (Hedge\nmaps facts across the submission's other applications\nasynchronously; watch the changes stream). Requires the\n`broker_submit` scope.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"session_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointCommand"}}}},"responses":{"200":{"description":"Checkpoint receipt","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckpointReceipt"}}}},"403":{"description":"broker_submit scope required"},"404":{"description":"Submission or application not found"},"409":{"description":"Stale revision or fingerprint; the body carries `code` and the current `application`"},"422":{"description":"Command rejected (`code: application_command_rejected`, e.g. an invalid classification)"},"503":{"description":"Save is busy (`code: application_busy`); retry the same operation after Retry-After"}}}},"/broker/submissions/{submission_id}/applications/{session_id}/request-quote":{"post":{"tags":["Carrier quotes"],"operationId":"requestApplicationQuote","summary":"Request a carrier quote for one application","description":"Queues the indication + quote request for the reviewed application.\nEvery revision token in the body must match the application you\nread (409 otherwise); the application must be `ready_for_quote`\n(422) and its program selected for quoting (409). Returns the\nrequest ledger row (`request_id`, `request_status`: queued or\nunconfirmed). Track it on the workspace's application\n(`request_state`, `result`) or via the api-quotes session. Requires\nthe `broker_submit` scope.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"session_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuoteCommand"}}}},"responses":{"200":{"description":"Quote request ledger row ({request_id, request_status, ...})"},"403":{"description":"broker_submit scope required"},"404":{"description":"Submission or application not found"},"409":{"description":"Reviewed application changed","or its program is not selected for quoting":null},"422":{"description":"Application not ready for a quote","or the carrier rejected these answers":null}}}},"/broker/submissions/{submission_id}/applications/{session_id}/business-descriptions":{"get":{"tags":["Carrier quotes"],"operationId":"listBusinessDescriptions","summary":"The carrier's business descriptions for an application","description":"The carrier's own business descriptions for this application (Coterie's\nclass list; the ISO class list for LIO and Blitz, whose class answers are ISO\ncodes), filtered to the submission's NAICS, product\nand state, with Hedge's best match first. `selected` is Hedge's match,\n`match.confidence` is `high` for one exact match, `check` for a shortlist and\n`none` otherwise; `choices[].available` is false for classes outside the\ncarrier's appetite. Confirm one as the application's business description\nanswer in its checkpoint before requesting a quote. Every response also\nnames the business for searching a class list: `naics`, `naics_description`,\n`operations` (the stated operations) and `suggested` (Hedge's ISO GL class\nfor that NAICS). A carrier whose class list is its question's own options\nreturns an empty `choices` with that description.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"session_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The carrier's business descriptions","Hedge's match first":null},"404":{"description":"Submission or application not found"}}}},"/broker/submissions/{submission_id}/applications/{session_id}/employers-classes":{"get":{"tags":["Carrier quotes"],"operationId":"listEmployersClasses","summary":"Workers' compensation class codes for an EMPLOYERS application","description":"The carrier's class catalog for the given `state` (2-letter code),\nfor an EMPLOYERS workers' compensation application on this\nsubmission. Use the returned codes as the classification answers in\nthat application's checkpoint. 404 for applications that are not\nEMPLOYERS WC.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"session_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"state","required":true,"schema":{"type":"string","minLength":2,"maxLength":2}}],"responses":{"200":{"description":"Class catalog for the state"},"404":{"description":"Submission or EMPLOYERS application not found"},"422":{"description":"Invalid state or the carrier catalog is unavailable"}}}},"/broker/submissions/{submission_id}/finalize":{"post":{"tags":["Submissions"],"operationId":"finalizeSubmission","summary":"Release a held submission","description":"Starts the run for a submission created with `hold: true` (or with\nan expected-documents manifest): Hedge matches carrier markets,\nsends the clearance email to the producer, opens the lanes and\nquotes the instant-quote markets. Idempotent — on a submission whose\nrun already started (a default create, or an earlier finalize) it\nreturns the same 202 without starting anything twice.\n\nMatching is asynchronous; it usually completes within about 5\nminutes (`typical_wait_seconds`). Poll\n`GET /broker/submissions/{id}/markets` for the three categories, or\nthe requirements endpoint, whose `marketing_status` flips to\n`matched` when lanes attach and distinguishes still-matching from\nno-appetite.\n\nA `mode: rater` submission (partner integrations) instead opens its\nchosen programs synchronously: `marketing_status` is `quoting` with\n`lanes` and `not_opened` (each program's reasons), or `closed` when\nnone of them can quote. A 422 `rater_start_failed` leaves the file\nheld (for example, no requested line or risk state could be read).\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"202":{"description":"Queued; matching runs asynchronously.","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"queued"},"marketing_status":{"type":"string","example":"matching"},"typical_wait_seconds":{"type":"integer","example":300},"detail":{"type":"string"}}}}}}}}},"/broker/submissions/{submission_id}/outstanding-requirements":{"get":{"tags":["Requirements"],"operationId":"getOutstandingRequirements","summary":"Everything the matched markets still need from you, as one batch","description":"The deduplicated union of outstanding broker-answerable items\nacross matched markets: unmet manifest requirements plus open\ncarrier-API questions, each carrying the market names it unlocks.\nItems the brief already answers are excluded. Deterministic and\nread-only; answer items with `POST .../outstanding-requirements/answers`.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Outstanding items","content":{"application/json":{"schema":{"type":"object","properties":{"submission_id":{"type":"string","format":"uuid"},"form_fill_active":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"source":{"type":"string"},"input":{"type":"string","description":"Widget type: text, number, bool, select, date, ..."},"options":{"type":"array","nullable":true,"items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"}}}},"markets":{"type":"array","items":{"type":"string"}},"how_to_provide":{"type":"string","nullable":true}}}},"answerable_count":{"type":"integer"},"markets_total":{"type":"integer"}}}}}},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/outstanding-requirements/answers":{"post":{"tags":["Requirements"],"operationId":"answerOutstandingRequirements","summary":"Answer outstanding items in a batch","description":"Apply typed answers to items the CURRENT outstanding view asks for\n(keys not in that view are reported as skipped, never written).\nAnswers land on the submission brief and are routed to live\ncarrier sessions automatically. Requires the `broker_submit`\nscope. Machine credentials must name `producer_email`.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["answers"],"properties":{"answers":{"type":"array","maxItems":60,"items":{"type":"object","required":["key","value"],"properties":{"key":{"type":"string","description":"An item key from GET .../outstanding-requirements"},"value":{"description":"Typed per the item's `input` (string","number":null,"boolean":null,"or option value)":null}}}},"producer_email":{"type":"string","description":"REQUIRED when authenticating with a machine credential; the active portal user the answers are attributed to."}}}}}},"responses":{"200":{"description":"Truthful applied/skipped report","content":{"application/json":{"schema":{"type":"object","properties":{"applied":{"type":"array","items":{"type":"string"}},"skipped":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"reason":{"type":"string"}}}},"routed":{"type":"integer","description":"Carrier sessions the answers were routed to"}}}}}},"403":{"description":"Token lacks the broker_submit scope"},"404":{"description":"Not found (or not your brokerage's)"},"422":{"description":"Missing/unknown producer_email for a machine credential"}}}},"/broker/submissions/{submission_id}/answers":{"post":{"tags":["Requirements"],"operationId":"recordPartnerAnswers","summary":"Record the agency's structured answers (partner integrations only)","description":"For an API partner acting for your brokerage (a token carrying the\npartner claim, with `broker_submit`) on a submission that partner\ncreated, before or after finalize. Any other caller, or a submission\nthe partner did not create, gets 404.\n\nEach answer is checked, and only a key a question carries is ever\nrecorded. An `api_program` answer is checked against the program's\n`questions` (`GET /broker/programs/{program_id}/application-schema`):\nby `question_id`, whose question's `key` it must send, or by `key`\nalone when one question carries it. Option values are the program's\nown JSON values and are compared exactly (`300000` is not\n`\"300000\"`). A `hedge_questions` answer is checked against the Hedge\nquestions (`POST /broker/hedge-questions`) by `key`; a select there\ntakes an option value or its label. Values are type-checked. Program\nanswers may address only the programs of a rater file, or of a\nstandard file's own lanes. An accepted answer is recorded on the\nsubmission as the agency's own answer under its `key`, which every\nHedge model, carrier application and rendered supplemental reads. A\nprogram answer also reaches that program's live carrier session once\none exists. Limits: 500 answers per request, 4,000 characters per\ntext answer, 20,000 characters of JSON per value (250,000 for a list\nvalue such as a carrier's location rows).\n\n`Idempotency-Key` (at most 128 characters) is required. Retrying the\nsame key with the same body returns the first result; the same key\nwith a different body is a 409.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"header","name":"Idempotency-Key","required":true,"schema":{"type":"string","maxLength":128}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["answers"],"additionalProperties":false,"properties":{"answers":{"type":"array","maxItems":500,"items":{"type":"object","required":["key","value","source"],"additionalProperties":false,"properties":{"key":{"type":"string","maxLength":200},"value":{"description":"JSON value typed per the question."},"source":{"type":"string","enum":["api_program","hedge_questions"]},"program_id":{"type":"string","format":"uuid","nullable":true,"description":"Required for api_program."},"question_id":{"type":"string","nullable":true,"maxLength":300}}}}}}}}},"responses":{"200":{"description":"The accepted count and each refused answer","content":{"application/json":{"schema":{"type":"object","required":["accepted","rejected"],"properties":{"accepted":{"type":"integer"},"rejected":{"type":"array","items":{"type":"object","required":["key","reason_code","message"],"properties":{"key":{"type":"string"},"reason_code":{"type":"string","enum":["unknown_key","invalid_value","not_allowed"]},"message":{"type":"string"}}}}}}}}},"403":{"description":"Token lacks the broker_submit scope"},"404":{"description":"Not a partner token","not the partner's submission":null,"or not your brokerage's":null},"409":{"description":"`idempotency_key_reused` (same key, different body) or `answers_in_progress` (retry the same request)"},"422":{"description":"`idempotency_key_required`, `idempotency_key_invalid`, or a body validation error"}}}},"/broker/submissions/{submission_id}/withdraw":{"post":{"tags":["Submissions"],"operationId":"withdrawSubmission","summary":"Withdraw a submission (pull the risk from marketing)","description":"Branches on placement state: an unfinalized draft is deleted on\nthe spot; a live placement becomes a withdrawal Hedge carries out\n(notices to every engaged market, then the submission closes as\nwithdrawn); a submission with a bound policy cannot be withdrawn\nhere (409; request a change on the policy instead). Idempotent.\nRequires the `broker_submit` scope. Machine credentials must name\n`producer_email` in the body; per-user tokens send no body.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"producer_email":{"type":"string","description":"REQUIRED when authenticating with a machine credential; the active portal user the withdrawal is attributed to."}}}}}},"responses":{"202":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"outcome":{"type":"string","enum":["discarded","withdrawal_requested","already_closed"]},"detail":{"type":"string"}}}}}},"403":{"description":"Token lacks the broker_submit scope"},"404":{"description":"Not found (or not your brokerage's)"},"409":{"description":"Bound policy (use a policy change request)","or the submission changed state mid-request":null},"422":{"description":"Missing/unknown producer_email for a machine credential"},"503":{"description":"The withdrawal could not be started; retry"}}}},"/broker/submissions/{submission_id}/bind-readiness":{"get":{"tags":["Submissions"],"operationId":"getBindReadiness","summary":"Bind progress summary (\"N of M items done\")","description":"Compact bind-progress counts for the submission, mirroring the\nportal's bind wizard so the two can never disagree. Returns 404\nwhile bind e-sign is not enabled for the environment.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Readiness summary","content":{"application/json":{"schema":{"type":"object","description":"`exists` is false when the submission has no active bind request.","properties":{"exists":{"type":"boolean"},"bind_request_id":{"type":"string","format":"uuid","nullable":true},"quote_id":{"type":"string","format":"uuid","nullable":true},"status":{"type":"string","nullable":true},"required_total":{"type":"integer"},"required_done":{"type":"integer"},"waiting_signatures":{"type":"integer","description":"Live signature envelopes still out with a signer"},"carrier_name":{"type":"string","nullable":true},"carrier_confirmed":{"type":"boolean"},"carrier_policy_number":{"type":"string","nullable":true}}}}}},"404":{"description":"Not found","not your brokerage's":null,"or bind e-sign not enabled":null}}}},"/broker/insureds":{"get":{"tags":["Submissions"],"operationId":"listInsureds","summary":"List or search your book of insureds","description":"Your brokerage's insureds on file with Hedge, most recently active\nfirst. With `q` it is the \"start from existing insured\" picker:\nreturns enough identity to prefill a new submission (name, entity\ntype, contact details, NAICS, mailing address). Pass a matching\nrow's `id` as `insured_id` on submission create to link the account.\nWith `include_stats=true` each row also carries submissions_count,\npolicies_count and last_activity_at for a book overview.\n","parameters":[{"in":"query","name":"q","schema":{"type":"string"},"description":"Case-insensitive match on the insured name."},{"in":"query","name":"limit","schema":{"type":"integer","minimum":1,"maximum":200,"default":10}},{"in":"query","name":"offset","schema":{"type":"integer","minimum":0,"default":0},"description":"Rows to skip, for paging large books."},{"in":"query","name":"include_stats","schema":{"type":"boolean","default":false},"description":"Adds submissions_count, policies_count and last_activity_at per\nrow (extra aggregate queries; leave off for typeahead use).\n"}],"responses":{"200":{"description":"Insured summaries","most recently updated first":null}}}},"/broker/insureds/{insured_id}":{"get":{"tags":["Submissions"],"operationId":"getInsured","summary":"Get one insured from your book","description":"One insured's canonical identity (name, DBA, entity type, contact\ndetails, NAICS/SIC, mailing address), active contacts, plus YOUR\nbrokerage's submissions and bound policies for it; the portal's\ninsured detail view in a single call.\n","parameters":[{"in":"path","name":"insured_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Insured detail"},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/policies":{"get":{"tags":["Policies"],"operationId":"listPolicies","summary":"List your brokerage's bound policies","description":"One row per policy: policy_number, carrier_name, status +\nstatus_label, premium, effective and expiration dates, and the\nsource submission_id.\n","responses":{"200":{"description":"Policy list","newest effective date first":null}}}},"/broker/policies/{policy_id}":{"get":{"tags":["Policies"],"operationId":"getPolicy","summary":"Get one policy","description":"Full policy detail: identifiers, coverage lines, term, carrier and\nunderwriting paper (with NAIC code and admitted status), the premium\nbreakdown (net premium, fees, taxes, total billed), YOUR commission\n(rate and amount), payment terms, and the downloadable documents\n(binder, policy, declarations) with their download paths.\n","parameters":[{"in":"path","name":"policy_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Policy detail"},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/policies/{policy_id}/document/{kind}":{"get":{"tags":["Policies"],"operationId":"downloadPolicyDocument","summary":"Download a policy document PDF","description":"Streams the binder, policy, or declarations PDF, brokerage-scoped.","parameters":[{"in":"path","name":"policy_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"kind","required":true,"schema":{"type":"string","enum":["binder","policy","declarations"]}}],"responses":{"200":{"description":"The PDF bytes (or a 307 redirect to hosted storage)","content":{"application/pdf":{}}},"404":{"description":"Policy or document not found"},"502":{"description":"Stored document could not be retrieved"}}}},"/broker/submissions/{submission_id}/bind-requests":{"post":{"tags":["Binding"],"operationId":"createBindRequest","summary":"Request to bind a released quote","description":"The broker's bind authority over the API. Drafts a bind request for\nthe chosen quote — the same request the Hedge portal's bind wizard\ncreates — allocating one response slot per pre-bind contingency the\ncarrier listed. Idempotent per carrier lane: re-posting for the same\nquote returns the existing draft (and records any new\n`attest_assumptions`).\n\n**Assumptions.** Instant quotes are obtained on recorded assumptions\n(values Hedge defaulted on the carrier application because the file\ndid not state them). They print on the signable application, so the\nretail agent must confirm them before the order reaches the carrier.\nThis is the only bind check, and it is surfaced here rather than\nholding a submitted request silently: while any remain unconfirmed\nthe response is **409 `assumptions_unconfirmed`** listing them; the\ndraft is kept. Re-POST with `attest_assumptions: true` (or the keys\nthe agent confirmed) to record the confirmation and receive the\ndraft. Nothing is sent to a carrier by this call.\n\n**Money.** Lanes whose bind collects card payment in the portal\n(direct-bill carriers) cannot be submitted over the API; `submit`\nanswers 422 with the reason. Requires the `broker_submit` scope;\nmachine credentials must name `producer_email`.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindRequestCreate"}}}},"responses":{"201":{"description":"The bind request draft (or the existing draft for this quote)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindRequestRead"}}}},"403":{"description":"broker_submit scope required"},"404":{"description":"Submission or quote not found (or not your brokerage's)"},"409":{"description":"Standing assumptions are not yet confirmed; the draft exists","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"$ref":"#/components/schemas/BindAssumptionsUnconfirmed"}}}}}},"422":{"description":"Not bindable (an indication, a superseded quote, a lane already binding), or producer_email missing/unknown for a machine credential"}}},"get":{"tags":["Binding"],"operationId":"listBindRequests","summary":"List this submission's bind requests","description":"Newest first, every status. Each row carries the same shape as the detail read.","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Bind requests","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/BindRequestRead"}}}}},"404":{"description":"Submission not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/bind-requests/{bind_request_id}":{"get":{"tags":["Binding"],"operationId":"getBindRequest","summary":"Get one bind request","description":"Current status, the assumptions still unconfirmed, each pre-bind\ncontingency with your response state and (while drafted) its upload\npath, and plain `next_steps`. Poll this, or the submission events\nfeed / webhooks for `bound`.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"bind_request_id","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Bind request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindRequestRead"}}}},"404":{"description":"Not found (or not your brokerage's)"}}}},"/broker/submissions/{submission_id}/bind-requests/{bind_request_id}/contingencies/{contingency_id}/document":{"post":{"tags":["Binding"],"operationId":"uploadBindContingencyDocument","summary":"Attach a document to a pre-bind contingency","description":"Multipart upload (`file`, a PDF up to 15 MB; optional `notes`, max\n2000 characters; `producer_email` for machine credentials). Each\ncall appends a file to that item — the same upload the portal\nwizard performs — and marks the response satisfied. Accepted only\nwhile the request is `drafted` (409 otherwise) and only for a\ncontingency on the request's selected quote (404 otherwise). PDF is\nthe only accepted type (415 for anything else); uploads count toward\nyour brokerage's daily document-upload limit (429 when reached).\nSignature-collected items (`signed_form` with e-sign) can also be\nsatisfied by uploading the signed PDF here.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"bind_request_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"contingency_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"A PDF","at most 15 MB":null},"notes":{"type":"string","maxLength":2000},"producer_email":{"type":"string"}}}}}},"responses":{"200":{"description":"The refreshed bind request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindRequestRead"}}}},"400":{"description":"Empty file"},"403":{"description":"broker_submit scope required"},"404":{"description":"Submission","bind request":null,"or contingency not found (a contingency not on the request's selected quote is not found)":null},"409":{"description":"The bind request is no longer drafted"},"413":{"description":"File exceeds the 15 MB limit"},"415":{"description":"Not a PDF"},"422":{"description":"Wrong document for a carrier-signed application","or producer_email missing/unknown for a machine credential":null},"429":{"description":"Daily document-upload limit reached"}}}},"/broker/submissions/{submission_id}/bind-requests/{bind_request_id}/submit":{"post":{"tags":["Binding"],"operationId":"submitBindRequest","summary":"Submit the bind request to Hedge for placement","description":"The wizard's own submit, same validation: the request moves from\n`drafted` to `submitted` and Hedge places the bind with the carrier\n(your brokerage's approval settings decide whether a Hedge reviewer\nlooks first). While assumptions remain unconfirmed this answers 409\n`assumptions_unconfirmed` — pass `attest_assumptions` in the body to\nconfirm and submit in one call. Surplus-lines placements need a\ndiligent search on file (422 says so); direct-bill card-payment lanes\nare portal-only (422). A `bound` event follows on the events feed\nand webhooks once the carrier binds.\n","parameters":[{"in":"path","name":"submission_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"path","name":"bind_request_id","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindRequestSubmit"}}}},"responses":{"200":{"description":"The submitted bind request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BindRequestRead"}}}},"403":{"description":"broker_submit scope required"},"404":{"description":"Submission or bind request not found"},"409":{"description":"Assumptions unconfirmed, already submitted, or the selected quote changed","content":{"application/json":{"schema":{"type":"object","properties":{"detail":{"oneOf":[{"$ref":"#/components/schemas/BindAssumptionsUnconfirmed"},{"type":"string"}]}}}}}},"422":{"description":"Not yet submittable (effective date out of range","diligent search owed":null,"required declaration or card payment missing":null,"producer_email missing)":null}}}},"/broker/payments":{"get":{"tags":["Payments"],"operationId":"listPayments","summary":"List invoice and payment status","description":"One row per bound submission with billing: submission_id,\ninsured_name, status + status_label, premium, invoice_url (the\nhosted invoice), updated_at. Read scope is enough.\n","responses":{"200":{"description":"Payment list","most recently updated first":null}}}},"/broker/appetite":{"get":{"tags":["Appetite"],"operationId":"checkAppetite","summary":"Which markets have appetite for a class of business","parameters":[{"in":"query","name":"q","required":true,"schema":{"type":"string"},"description":"Risk description, e.g. roofing contractor"},{"in":"query","name":"state","schema":{"type":"string"}},{"in":"query","name":"lob","schema":{"type":"string"}}],"responses":{"200":{"description":"Ranked markets with lines and matched programs"},"429":{"description":"Daily appetite-check limit reached"}}}},"/broker/appetite/search":{"post":{"tags":["Appetite"],"operationId":"searchPlacements","summary":"Structured appetite search (query + lines + state)","description":"The portal's placement search: a free-text risk description plus\noptional lines and state, returning ranked markets with matched\nprograms and their Hedge category. Same daily limit as `GET /broker/appetite`.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","maxLength":2000},"state":{"type":"string","minLength":2,"maxLength":2},"lines":{"type":"array","maxItems":30,"items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Ranked markets with matched programs"},"429":{"description":"Daily appetite-check limit reached"}}}},"/broker/catalog/query":{"post":{"tags":["Appetite"],"operationId":"queryMarketCatalog","summary":"The programs Hedge would try for lines, state and NAICS","description":"Deterministic, read-only (no submission is created). Returns the\nprograms Hedge attaches on line of business for the request, after\nyour brokerage's market, program and line settings and Hedge's state\nfootprint: connected carrier APIs (`channel: api`) and portals Hedge\ndrives (`channel: portal`). Email and manual-portal markets are\nlisted only with `all_channels: true` (`channel: email` and\n`channel: portal`), each with an `appetite` status. Programs that\nonly ever return a non-binding indication are never listed. A\nlisting is a potential route, not a quote; for API and portal\nprograms the carrier's own application answers appetite.\n\nHedge sends ONE program per market, channel and line. Every eligible\nsibling is listed; exactly one per market, channel and line is the\ndefault (`default_lines`), and the others name it in\n`alternative_of`. Programs that cannot be tried are in `excluded`\nwith reason codes: your own Markets settings\n(`broker_market_excluded`, `broker_program_excluded`,\n`broker_program_line_excluded`), the program's lines and states\n(`unsupported_requested_line`, `requested_coverage_mismatch`,\n`package_companion_not_requested`, `program_state_excluded`,\n`market_state_excluded`, `exposure_state_excluded`), Hedge's state footprint\n(`brokerage_state_unavailable`), the request's facts\n(`program_class_excluded`, `below_program_revenue_floor`,\n`above_program_revenue_limit`), or `program_unavailable` when the\nprogram cannot be tried right now.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogQuery"}}}},"responses":{"200":{"description":"Offered and excluded programs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatalogResult"}}}},"422":{"description":"Invalid body, or `{code: unknown_line, value}` for a line Hedge does not recognize"}}}},"/broker/hedge-questions":{"post":{"tags":["Appetite"],"operationId":"getHedgeQuestions","summary":"The Hedge supplemental questions for a risk (no submission needed)","description":"Deterministic and read-only. Returns the curated core questions of\nthe Hedge supplemental form(s) that apply to the risk, merged so a\nshared `key` is asked once. Forms resolve in this order, at most\nfour: the Hedge forms the selected `program_ids` require, the class\nform for the NAICS (the most specific prefix), or for the business\n`description` when the NAICS names no class form, then the coverage\nform of each requested line (liquor,\nauto, cyber, workers' comp and so on; the general GL and property\nforms only when no class form covers the line). A form Hedge asks\nabout but does not send as a PDF (the general GL supplemental) is not\nin `forms`; its questions are. An empty `forms` and `sections` is a\nvalid answer: send the note and documents only.\n\nAnswer with `POST /broker/submissions/{submission_id}/answers`\n(`source: hedge_questions`).\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["lines"],"additionalProperties":false,"properties":{"lines":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"string"},"description":"Canonical lines of business."},"state":{"type":"string","description":"Two-letter US state."},"naics":{"type":"string","description":"2 to 6 digits."},"program_ids":{"type":"array","maxItems":100,"items":{"type":"string","format":"uuid"},"description":"The selected Hedge (portal and email) programs."},"description":{"type":"string","maxLength":1000,"description":"Optional: the agency's description of the business, which class keywords match (for example cannabis, which has no NAICS)."}}}}}},"responses":{"200":{"description":"The resolved forms and their questions","content":{"application/json":{"schema":{"type":"object","required":["version","forms","sections"],"properties":{"version":{"type":"string","description":"Changes when the question sets change, e.g. `HEDGE_14@2026-09-28.1`; `none` when no form applies."},"forms":{"type":"array","items":{"type":"object","required":["form_key","title"],"properties":{"form_key":{"type":"string","description":"The Hedge form's key, e.g. HEDGE_14_RESTAURANT_BAR_AND_TAVERN_SUPPLEMENTAL."},"title":{"type":"string"}}}},"sections":{"type":"array","items":{"type":"object","required":["id","title","questions"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"questions":{"type":"array","items":{"$ref":"#/components/schemas/SharedQuestion"}}}}}}}}}},"422":{"description":"Invalid body, or `{code: unknown_line}` for a line Hedge does not write"},"503":{"description":"`hedge_questions_unavailable`: try again shortly"}}}},"/broker/appetite/guide":{"get":{"tags":["Appetite"],"operationId":"downloadAppetiteGuide","summary":"Download the Hedge Appetite & Markets Guide (PDF)","responses":{"200":{"description":"The PDF bytes","content":{"application/pdf":{}}}}}},"/broker/markets/{market_id}/requirements":{"get":{"tags":["Requirements"],"operationId":"getMarketRequirements","summary":"Requirements forecast for a market + line (pre-submission)","parameters":[{"in":"path","name":"market_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"lob","required":true,"schema":{"type":"string"}},{"in":"query","name":"state","schema":{"type":"string"}}],"responses":{"200":{"description":"Baseline forms + authored program requirements (broker-safe)"}}}},"/broker/market-access":{"get":{"tags":["Market access"],"operationId":"getMarketAccess","summary":"The markets this brokerage receives quotes from, with per-program and per-line toggles","description":"One row per market Hedge has enabled for your brokerage, each with its per-program breakdown and each program's line switches. A toggle that is off stops NEW submissions from being marketed there; in-flight submissions are unaffected. Readable by any signed-in broker user.","responses":{"200":{"description":"Rows of {market_id, name, enabled, programs: [{program_id, name, description, enabled, lines: [{slug, label, enabled}]}]}"}}},"put":{"tags":["Market access"],"operationId":"setMarketAccess","summary":"Turn a whole market on or off (admin)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["market_id","enabled"],"properties":{"market_id":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The refreshed market-access table"},"403":{"description":"Admin role required"},"404":{"description":"Market not visible to this brokerage"}}}},"/broker/market-access/program":{"put":{"tags":["Market access"],"operationId":"setProgramAccess","summary":"Turn one program of a market on or off (admin)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["program_id","enabled"],"properties":{"program_id":{"type":"string","format":"uuid"},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The refreshed market-access table"},"403":{"description":"Admin role required"},"404":{"description":"Program not visible to this brokerage"}}}},"/broker/market-access/program-line":{"put":{"tags":["Market access"],"operationId":"setProgramLineAccess","summary":"Turn a single line of business within a program on or off (admin)","description":"Toggles one line the program lists (see the program's lines in GET /broker/market-access). Turning off every line a program lists is equivalent to turning the program off.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["program_id","lob_slug","enabled"],"properties":{"program_id":{"type":"string","format":"uuid"},"lob_slug":{"type":"string","description":"Canonical line-of-business slug","e.g. commercial_general_liability":null},"enabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"The refreshed market-access table"},"403":{"description":"Admin role required"},"404":{"description":"Line not listed by this program","or program not visible":null}}}},"/broker/market-connections":{"get":{"tags":["Market access"],"operationId":"listMarketConnections","summary":"Your brokerage's own carrier appointments connected to Hedge","description":"Bring-your-own appointments (today: Next Insurance). Quotes for your\nsubmissions then run on your own account with that carrier.\nRequires `broker_submit`.\n","responses":{"200":{"description":"Rows of {provider_key, provider_name, status, label, allowed_states, last_validated_at, last_error}"}}}},"/broker/market-connections/next-insurance":{"put":{"tags":["Market access"],"operationId":"connectNextInsurance","summary":"Connect your Next Insurance appointment","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["referral_url"],"properties":{"referral_url":{"type":"string","description":"Your Next referral / client-binds-on-their-own link."}}}}}},"responses":{"200":{"description":"The connection row"},"422":{"description":"The link could not be validated"}}},"delete":{"tags":["Market access"],"operationId":"disconnectNextInsurance","summary":"Disconnect your Next Insurance appointment","responses":{"204":{"description":"Disconnected"}}}},"/broker/programs":{"get":{"tags":["Programs"],"operationId":"listPrograms","summary":"The carrier programs (products) your brokerage can quote through Hedge","description":"The same catalog as GET /broker/market-access, flattened to one row\nper program with its broker category. `instant_quote` programs are\nquoted live through a carrier API and expose an application question\nschema (below) that your own application builder can plug into;\n`binding` programs Hedge quotes for you; `specialty` programs need\ncompleted ACORDs, program requirements and loss runs. Filters\ncombine (AND). Read scope is enough.\n","parameters":[{"in":"query","name":"category","schema":{"type":"string","enum":["instant_quote","binding","specialty"]}},{"in":"query","name":"lob","schema":{"type":"string"},"description":"Canonical line slug or common alias (gl","wc)":null},{"in":"query","name":"state","schema":{"type":"string","minLength":2,"maxLength":2}}],"responses":{"200":{"description":"Programs, instant-quote first, then by market and name","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Program"}}}}},"422":{"description":"Unknown category"}}}},"/broker/programs/{program_id}/application-schema":{"get":{"tags":["Programs"],"operationId":"getProgramApplicationSchema","summary":"The application question schema for an instant-quote program","description":"Exactly the questions Hedge's carrier integration asks for this\nprogram — the schema the carrier application is filed on — projected\nfor your own application builder: sections of questions with stable\nkeys, labels, types, options, help, and `depends_on` visibility\ndependencies. Collect answers against these keys, then save them to\nthe submission's application via the application-workspace\ncheckpoint. Optional `lob`/`state` check that the program lists that\nline / state.\n\nServed from Hedge's schema cache only — the schema Hedge's own\nquoting already filed on; this read never calls the carrier. Until\nHedge's first quote with a program the response is 404\n`code: application_schema_unavailable` (the list endpoint's\n`application_schema_available` tells you in advance). Programs Hedge\nquotes itself have no schema: 404 `code: no_application_schema`\npointing at GET /broker/markets/{market_id}/requirements.\n\n`questions` (with `schema_version`) is the same application in the\nshared question shape: exactly the questions the Hedge broker\nworkspace asks for this program, one flat list in order. `key` is\nthe shared answer key: Hedge's fact key where the program's question\nmeans the same fact in the same form (so one answer can prefill\nevery program that asks it), otherwise\n`program.<program_slug>.<id>`. `show_if` / `required_if` are the\nfull condition rules, keyed by `key`. Pass `lob` for the coverage\nbeing quoted: programs whose questions depend on the products Hedge\nselects for a line (Blitz) resolve them from it. `schema_version`\nchanges whenever `questions` change; cache per `schema_version`.\n","parameters":[{"in":"path","name":"program_id","required":true,"schema":{"type":"string","format":"uuid"}},{"in":"query","name":"lob","schema":{"type":"string"}},{"in":"query","name":"state","schema":{"type":"string","minLength":2,"maxLength":2}}],"responses":{"200":{"description":"The projected question schema and the program's shared questions","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ProgramApplicationSchema"},{"type":"object","required":["schema_version","questions"],"properties":{"schema_version":{"type":"string","description":"Content hash of `questions`."},"questions":{"type":"array","items":{"$ref":"#/components/schemas/SharedQuestion"}}}}]}}}},"404":{"description":"Program not visible to your brokerage or not available for the given line/state (plain detail); not an instant-quote program (`code: no_application_schema`); or no schema cached yet (`code: application_schema_unavailable`)"}}}}},"webhooks":{"submission.events":{"post":{"tags":["Webhooks"],"operationId":"receiveSubmissionEvents","summary":"New submission events, pushed to your registered endpoint","description":"Hedge POSTs this message to each webhook endpoint your brokerage\nhas registered (broker portal → Settings → Webhooks, admins only)\nwhenever a submission gains newly-visible events; the SAME event\nobjects, vocabulary and visibility rules as\n`GET /broker/submissions/{submission_id}/events`, delivered\nwithin about a minute of becoming visible. An endpoint receives\nevents from its creation onward; history is not replayed.\n\n**Verifying.** Every delivery is signed with your endpoint's\n`whsec_` secret (shown exactly once at creation; rotate by\nrevoking and re-creating). Headers are the standard-webhooks /\nsvix scheme, verifiable with any svix SDK:\n\n- `svix-id`; the delivery id, STABLE across every retry and\n  manual redelivery: your idempotency key.\n- `svix-timestamp`; unix seconds; reject stale timestamps\n  (±5 minutes is the conventional tolerance).\n- `svix-signature`; `v1,` + base64(HMAC-SHA256(secret,\n  `{id}.{timestamp}.{body}`)) over the exact bytes received.\n\n**Delivery semantics.** At-least-once: dedupe on `svix-id`.\nWithin one submission, deliveries arrive in order; across\nsubmissions there is no ordering guarantee. An event's `(id,\ntype)` pair can arrive AGAIN with an upgraded `type`; e.g. a\n`status_changed` later re-delivered as `quote_received` once the\nquote is relayed to you; so treat `(id, type)` as the event\nidentity; deduping webhook events by `id` alone will drop quote\narrivals. (The polling feed has no such re-emission; this is\npush-only behavior, and it is how a relay that happens hours\nafter the underlying status row is still pushed to you.)\n\n**Acknowledging.** Respond 2xx within 10 seconds; the body is\nignored. Redirects are treated as failures. Anything else is\nretried with backoff for up to 8 attempts over 24 hours; the\ndelivery is then parked (re-send it from the portal's delivery\nlog). Repeated exhausted deliveries auto-disable the endpoint;\na successful test-send from the portal re-enables it and queued\nevents resume.\n\nA `ping` message (`{\"type\": \"ping\", ...}`, same signature scheme)\nis sent by the portal's test button; acknowledge it like any\nother delivery.\n\n**Filtering.** An endpoint's optional `event_types` filter names\nthe event types it wants (`market_attached`, `quote_received`,\n`status_changed`, `declined`, `withdrawn`, `blocked`, `bound`) and\nmay include `message` to also receive `submission.message`\ndeliveries (below). No filter = everything.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["type","submission_id","events"],"properties":{"type":{"type":"string","const":"submission.events"},"submission_id":{"type":"string","format":"uuid"},"events":{"type":"array","description":"Newly-visible events, oldest first; the exact object shape of the polling feed's `events` array.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["market_attached","quote_received","status_changed","declined","withdrawn","blocked","bound"]},"occurred_at":{"type":"string","format":"date-time"},"market":{"type":"object","properties":{"name":{"type":"string"},"lines":{"type":"array","items":{"type":"string"}},"lane_id":{"type":"string","format":"uuid","nullable":true},"category":{"$ref":"#/components/schemas/ProgramCategory"}}},"status":{"type":"string"},"status_label":{"type":"string"},"detail":{"type":"string","nullable":true}}}}}}}}},"responses":{"200":{"description":"Acknowledge with any 2xx within 10 seconds; response body is ignored."}}}},"submission.message":{"post":{"tags":["Webhooks"],"operationId":"receiveSubmissionMessage","summary":"A new thread message (Hedge's or yours), pushed to your endpoint","description":"Hedge POSTs this message whenever a new message becomes visible\non a submission's thread; the SAME object, vocabulary and\nvisibility rules as `GET /broker/submissions/{submission_id}/thread`\n(Hedge's emails to your brokerage, your replies, and assistant\nchat in both directions; never carrier or insured correspondence),\ndelivered within about a minute of becoming visible. One message\nper delivery; a burst arrives as consecutive deliveries in order.\nAn endpoint receives messages from its creation onward (and, for\nendpoints that predate this message type, from the moment it\nshipped); history is not replayed.\n\nSigning, `svix-id` dedupe, at-least-once delivery, in-order\ndelivery within a submission, acknowledgement and retry rules are\nexactly those of `submission.events`. Messages never re-arrive\nwith a changed body; dedupe on `svix-id` (or on `message.id`).\nDelivered to endpoints whose `event_types` filter is empty or\nincludes `message`.\n","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["type","submission_id","message"],"properties":{"type":{"type":"string","const":"submission.message"},"submission_id":{"type":"string","format":"uuid"},"message":{"$ref":"#/components/schemas/ThreadMessage"}}}}}},"responses":{"200":{"description":"Acknowledge with any 2xx within 10 seconds; response body is ignored."}}}}}}