Conventions
A few rules hold across every endpoint. Learn them once and the rest of the API is predictable.
One call in, the system runs
Section titled “One call in, the system runs”Creating a submission is the same act as emailing Hedge a risk. POST /broker/intake (text and/or PDFs) and POST /broker/submissions (structured
JSON) both create the submission and start the run as soon as the create
commits: Hedge extracts the risk, matches appetite, emails the producer the
clearance listing every market being tried, opens the lanes, and quotes the
instant-quote markets on recorded favorable assumptions. Documents uploaded
afterwards flow into the open lanes.
hold: true(form field or body key) defers the run. The response saysmarketing_status: awaiting_finalization;POST .../finalizereleases it.finalizeis idempotent: on a submission whose run already started it returns the same202without starting anything twice.- Every create response carries
marketing_status(matchingorawaiting_finalization) andnext_step, the call to make next. - Matching is asynchronous and usually lands within about five minutes
(
typical_wait_seconds). An empty markets view duringmatchingis not “no appetite”; poll again.GET .../requirementsdistinguishesmatching,matched,not_startedandno_markets_matched.
The three market categories
Section titled “The three market categories”GET /broker/submissions/{id}/markets groups every lane the way the clearance
email does. All three categories are always present, in this order, even when
empty:
category |
label |
What it is |
|---|---|---|
instant_quote |
Hedge Instant Quote | Connected carrier APIs, quoted live on recorded favorable assumptions. |
binding |
Hedge Binding | Markets Hedge quotes for you. |
specialty |
Hedge Specialty | Email markets that need the completed ACORDs, program requirements and loss runs. |
Each lane carries status/status_label, submit_ready, needs_from_you
(broker-actionable asks, present only while the lane is gapped),
assumptions and released quotes. The same program_category values appear
on GET /broker/programs.
Assumptions are attestations
Section titled “Assumptions are attestations”An assumption is a value Hedge defaulted on a carrier application because the
file did not state it. Each one is a pre-bind attestation the producer must
confirm. On a lane, assumptions[].confirmed is false while it still stands
and true once confirmed. A bind request lists the ones still open as
unconfirmed_assumptions.
producer_email for machine credentials
Section titled “producer_email for machine credentials”Machine tokens (the client_credentials grant) carry no broker identity. Every
write made with one names the producing broker with producer_email, an
active portal user of your brokerage: intake, submissions, thread replies,
outstanding-requirements/answers, withdraw, bind-requests, contingency
uploads and bind-requests/{id}/submit. The action is attributed to that
broker in the portal and in the clearance email. Missing or unknown
producer_email returns 422. Per-user tokens ignore the field.
Idempotency
Section titled “Idempotency”POST /broker/intake, POST /broker/submissions and POST .../thread accept
an Idempotency-Key header. Re-sending the same key replays the saved result
(intake and create: the same submission with its documents; thread: the same
message and turn) instead of creating a duplicate. A key reused with different
inputs, or still in flight, returns 409. The hedge CLI sends a random key
on every run and accepts --idempotency-key for scripted retries.
Application-workspace commands (checkpoint, request-quote) are idempotent
per operation_id and use optimistic concurrency: echo the revision tokens you
read; a mismatch returns 409 with the current application.
Cursors
Section titled “Cursors”GET .../thread and GET .../events are cursor-paged. The end-of-stream
signal is the cursor, never page length. A non-null next_cursor means more
may exist: store it and call again with since=<cursor> until you receive
null. Ids are stable, so re-reading an older cursor is always safe; dedupe by
id. Prefer webhooks for push delivery of the same objects.
409 assumptions_unconfirmed
Section titled “409 assumptions_unconfirmed”POST .../bind-requests and POST .../bind-requests/{id}/submit refuse to go
forward while any assumption behind the quote stands unconfirmed. The response
is 409 with a structured detail:
{ "detail": { "code": "assumptions_unconfirmed", "message": "…", "bind_request_id": "…", "assumptions": [ { "key": "years_in_business", "label": "In business 3+ years", "value": 3 } ] }}The draft is kept. Show the retail agent each statement; once they have
reviewed them, re-POST with attest_assumptions: true (every standing
assumption) or a list of the confirmed keys. Keys matching no standing
assumption are ignored, never invented. The confirmation is recorded on the
bind request under the producing broker and is the only bind check; nothing is
sent to a carrier until submit.
Webhooks and event_types
Section titled “Webhooks and event_types”Register endpoints in the broker portal under Settings → Webhooks (brokerage admins; the management API is portal-session-only by design). Hedge POSTs two payload types:
type |
When | Body |
|---|---|---|
submission.events |
New submission events become visible | The same event objects as GET .../events |
submission.message |
A new thread message becomes visible | { type, submission_id, message: ThreadMessage }, the same object as GET .../thread |
An endpoint’s optional event_types filter names the feed event types it
wants (market_attached, quote_received, status_changed, declined,
withdrawn, blocked, bound) and may include message to also receive
submission.message. No filter means everything. Deliveries are signed
(svix-compatible), at-least-once and in order within a submission; acknowledge
with any 2xx within 10 seconds and dedupe on svix-id. The full contract is
under the Webhooks tag in the API Reference.
Requests
Section titled “Requests”-
JSON over HTTPS. Request and response bodies are JSON; send
Content-Type: application/jsonon requests with a body. Exceptions: the OAuth token and device endpoints useapplication/x-www-form-urlencoded, and file uploads (/broker/intake,.../documents, bind contingency documents) usemultipart/form-data. -
Bearer auth. Every request carries a short-lived OAuth 2.1 bearer token:
Authorization: Bearer <token>Machine credentials are exchanged for short-lived tokens and never sent on API requests. See Authentication.
-
Base URL. All endpoints live under
https://api.hedgespecialty.com/api/v1.
Status codes
Section titled “Status codes”| Code | Meaning |
|---|---|
200 OK |
The request succeeded. |
201 Created |
A resource was created (a submission, a bind request draft). |
202 Accepted |
Accepted and processing asynchronously (finalize, a thread reply, a withdrawal). |
400 Bad Request |
Malformed request, or a document id that does not belong to the submission. |
401 Unauthorized |
The token is missing, expired, or invalid. |
403 Forbidden |
The token is valid but lacks the scope, or the surface is portal-session-only. |
404 Not Found |
The resource does not exist, or belongs to another brokerage (see Data scoping). |
409 Conflict |
The request conflicts with current state: assumptions_unconfirmed, a reused Idempotency-Key, a stale revision, a bound policy on withdraw. |
413 Content Too Large |
A file is over the limit: 15 MB per PDF on intake and documents, 25 MB on bind contingency documents. |
415 Unsupported Media Type |
Not a supported document type. |
422 Unprocessable Content |
Validation failed: missing text/insured_name, missing producer_email for a machine credential, an unbindable quote, an application not ready for a quote. |
429 Too Many Requests |
Rate limited (the daily create and upload limits). Back off and retry. |
503 Service Unavailable |
A dependency is temporarily unavailable (text extraction, a carrier schema); your input is preserved, retry. |
Errors
Section titled “Errors”Errors return a JSON body with a detail field. Simple failures carry a
string; structured failures carry an object with a stable code:
{ "detail": "Not authorized to act on this account." }{ "detail": { "code": "no_application_schema", "message": "…" } }Validation errors from the framework carry a list of {loc, msg, type}. Use
the status code and code to react programmatically and message/detail
for the human explanation.
Scopes
Section titled “Scopes”Read endpoints accept a token with broker_mcp; endpoints that create or
change anything require broker_submit. A valid token with the wrong scope
returns 403 Forbidden.
| Scope | Grants |
|---|---|
broker_mcp |
Read: submissions, markets, thread, requirements, programs and application schemas, application workspace, bind requests, policies, payments, appetite. |
broker_submit |
Write: intake and create, upload documents, reply on the thread, answer outstanding asks, withdraw, finalize a held submission, checkpoint and request quotes on applications, create/upload/submit bind requests. |
Data scoping
Section titled “Data scoping”Every token is bound to exactly one brokerage, and all data is scoped to that brokerage. The brokerage comes from the authenticated principal, never from the request body, so you cannot read or write another brokerage’s data.