Webhooks

Feed a calculator's inputs from your own API — available on the Extra plan ($50/mo).

Instead of a calculator opening with blank fields, a webhook lets it open pre-filled with a specific visitor's real data — their income from your billing system, their height/weight from a patient record, whatever your own API already knows. This is a pull, not a push: on every widget load, our server fetches your endpoint and merges the result into the calculator's fields. Your endpoint is never called from the visitor's browser, and your API's own auth token never appears in public page HTML.

The contract

Your endpoint receives a plain GET request and returns a JSON object. Keys that match the calculator's own field names become pre-filled values; anything else in the response is ignored, and a field your endpoint doesn't mention just keeps its normal default. There's no separate field-mapping step — the response's keys are the calculator's field keys.

For example, the bmi calculator's fields are weight and heightCm (or height/weightKg depending on the unit system displayed) — a webhook for it should return:

{ "weight": 82, "heightCm": 178 }

Configuring one

Set it from your dashboard's Widget Customizer (a "Webhook" field appears once your account is on the Extra plan), or directly via PUT /v1/widget-config/:calcId:

curl -X PUT https://exactcalcs.com/v1/widget-config/bmi \
  -H "Authorization: Bearer <your JWT>" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "webhook": {
        "url": "https://your-api.example.com/lead-data",
        "headers": { "Authorization": "Bearer sk_your_own_token" }
      }
    }
  }'

headers is optional — set it if your endpoint needs its own auth. It's sent as request headers when we call your URL; it's never exposed to the browser.

What can go wrong, and what happens

A webhook is never allowed to break the calculator for a visitor. If your endpoint is slow (we time out at 5 seconds), returns a non-2xx status, returns something that isn't a JSON object, or is unreachable — the calculator just opens with its normal defaults, silently. There's nothing to catch or handle on your side.

Two things we reject outright, both at save time and again on every fetch:

  • A URL that isn't http or https.
  • A URL that resolves to a private/internal address (localhost, 127.0.0.1, 10.x, 192.168.x, link-local, and similar ranges) — this closes off using the feature to make our server probe internal networks.

Plan requirement

Webhooks are gated on the Extra plan both when you save a config (an attempt on Free or Base gets a 403 with a clear message) and again on every widget load — downgrading stops a previously-configured webhook from firing immediately, not just on its next edit. See pricing.