Skip to content

Conventions

A few rules hold across every endpoint. Learn them once and the rest of the API is predictable.

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 says marketing_status: awaiting_finalization; POST .../finalize releases it. finalize is idempotent: on a submission whose run already started it returns the same 202 without starting anything twice.
  • Every create response carries marketing_status (matching or awaiting_finalization) and next_step, the call to make next.
  • Matching is asynchronous and usually lands within about five minutes (typical_wait_seconds). An empty markets view during matching is not “no appetite”; poll again. GET .../requirements distinguishes matching, matched, not_started and no_markets_matched.

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.

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.

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.

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.

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.

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.

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.

  • JSON over HTTPS. Request and response bodies are JSON; send Content-Type: application/json on requests with a body. Exceptions: the OAuth token and device endpoints use application/x-www-form-urlencoded, and file uploads (/broker/intake, .../documents, bind contingency documents) use multipart/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.

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 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.

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.

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.