Webhooks & integrations
EstimateIQ integrates with external systems — a carrier portal, a CRM, a Power Automate flow, and XactAnalysis — through a small webhook surface. External status strings normalize into the internal ball-in-court state machine, and status changes fan back out to a downstream system.
Inbound: push a status in
POST /api/webhooks/statusAuthenticate with the shared token header x-webhook-token: <token> (or Authorization: Bearer
<token> — both accepted; the token is the Worker’s WEBHOOK_TOKEN, falling back to
REVSRC_SECRET_KEY). If no token is configured the endpoint is open (preview only).
Body — identify the estimate by one of estimateNo | claimNo | id, plus a status:
{ "estimateNo": "EST-24117-MIT", "status": "approved", "note": "Carrier approved as revised", "actor": "State Farm"}| Field | Required | Notes |
|---|---|---|
id / estimateNo / claimNo | one of | How EstimateIQ resolves the target estimate. |
status | yes | Any external status string — mapped to an internal status. |
note | no | Free text, recorded on the estimate timeline. |
actor | no | Who made the change (e.g. the carrier). |
approvedRcv | no | Approved RCV amount on approved / settled. |
On success EstimateIQ resolves the estimate, maps the status, recomputes the ball, appends a webhook
event, fires the outbound webhook, and returns the new state. Failure modes: 401 (unauthorized),
404 (estimate not found), 422 (unmapped status).
External → internal status map
Inbound status strings match case-insensitively, then by longest-key substring, so phrases like
"carrier - revision requested" still resolve. The default map (overridable per deployment via the
statusMap setting):
| External phrase(s) | Internal status |
|---|---|
draft, new, open | draft |
submitted, sent, received, acknowledged | submitted |
in review, desk audit, auditing, under review | in_review |
revision requested, returned, supplement, rejected, kickback | revision_requested |
responded, resubmitted | responded |
approved, accepted | approved |
settled, paid | settled |
closed | closed |
XactAnalysis lifecycle sync
POST /api/webhooks/xactanalysisThe carrier estimating platform pushes lifecycle events; EstimateIQ creates or advances the tracker
and archives the correspondence into the estimate thread + triage inbox. Same
x-webhook-token auth. The event field selects the action:
event | Effect |
|---|---|
assignment | Creates a new tracker (needs estimateNo, carrierId, insured) and logs an inbound assignment email. |
revision | Logs an auditor revision (parse + rules + follow-up) and archives the note. |
submitted | Records a resubmission to the carrier. |
approved / settled | Marks the estimate approved / settled and archives the notice. |
status | Generic status change, mapped through the status map. |
{ "event": "revision", "estimateNo": "EST-24117-MIT", "note": "Need day-6 moisture reading.", "amount": 14820 }Discovery & test
GET /api/webhooks/status # live schema + status map (no auth; safe to read)GET /api/webhooks/xactanalysis # XactAnalysis event schema (no auth)POST /api/webhooks/test # echoes your payload back (connection test)The GET discovery endpoints are self-documenting — they return the auth requirement, the body
schema, an example, and (for status) the current status map, so an integrator can wire up a flow
without reading source.
Outbound: fire events on change
When a status change lands, EstimateIQ POSTs a payload to the URL in the outboundWebhookUrl
setting (set in Settings or via the API). If no URL is configured, the send is skipped. Best-effort —
it never throws into the inbound request.
{ "event": "status_changed", "estimateNo": "EST-24117-MIT", "claimNo": "...", "id": "...", "status": "Approved", "internalStatus": "approved", "ballInCourt": "done", "at": "2026-06-30T00:00:00.000Z"}Inbound carrier-mail pipeline
Carrier mail can also arrive as a batch on the MAIL_INGEST queue. The Worker’s queue() handler:
- Archives each raw message to R2 before parsing.
- Matches the subject against the enabled subject rules to pull an estimate number.
- If it resolves to a known estimate, kicks the durable
RevisionWorkflow(persist → parse → apply revision + rules → arm SLA alarm → notify). - If not, leaves the message archived and unmatched for inbox triage.
Transient failures retry (up to max_retries, then the dead-letter queue).
Power Automate example
Add an HTTP action to your flow:
- Method:
POST· URI:https://esb.guru/api/webhooks/status - Headers:
x-webhook-token: @{variables(‘EstimateIQToken’)}·Content-Type: application/json - Body:
{ "estimateNo": "@{triggerBody()?['estimateNumber']}", "status": "@{triggerBody()?['carrierStatus']}", "note": "@{triggerBody()?['statusNote']}", "actor": "@{triggerBody()?['carrierName']}"}Store the token in a secure variable or the flow’s connection reference — never inline it.