Widget leads are one way
The new-lead webhook does not bring HighLevel changes back. Leads your HighLevel forms send to a widget's form leads URL with an external_id can sync stage and price both ways. See custom integrations.
Measured Bid posts each new lead to a webhook. In GoHighLevel, a workflow with the Inbound Webhook trigger receives it and creates or updates the contact. There's no native HighLevel app yet. You set this up once in your workflow builder.
You need a Measured Bid widget and access to Automation in the HighLevel sub-account the leads should land in.
In HighLevel, open Automation and create a workflow. Add the Inbound Webhook trigger and copy the webhook URL it shows.
Open your widget's settings, find New-lead alerts and paste the URL into Webhook. Save. The address must start with https://.
Open your homeowner link, get a price for an address and send the form. It counts as one estimate. Back in HighLevel, click Test Trigger, pick the request that arrived and save it as the sample.
Add the Create/Update Contact action. Map firstName, lastName, phone and email, and street, city, state and zip to the contact's address fields. HighLevel needs a phone or an email, and every Measured Bid lead has a phone number.
Create custom fields for what you want to keep, such as estimate low, estimate high, trade and lead source. Map estimateLow, estimateHigh, service and the utm values to them.
Add the actions you already use: a tag, an opportunity in your pipeline, a task or an alert to your team. Then publish the workflow.
One JSON post per new lead. None of the keys have spaces, which HighLevel's field mapping needs.
The webhook carries the contact details, the range, the trade and the source. The measured quantities are in the new-lead email. The lead in your dashboard has those, plus the homeowner's answers, the line-item dollars and the map of what was measured.
{
"leadId": "5b0e2c1a-8f3d-4c7e-9a61-2d4f7b8c9e10",
"brand": "sierra-gutter-co",
"brandName": "Sierra Gutter Co.",
"service": "gutters",
"guardProduct": {
"id": "sample-mesh",
"name": "Micro-mesh aluminum"
},
"quoteId": "9c4d7e2f-1a3b-4c5d-8e6f-7a8b9c0d1e2f",
"formattedAddress": "412 Sample Ridge Ct, Roseville, CA 95661, USA",
"name": "Jordan Example",
"phone": "(916) 555-0114",
"email": "jordan@example.com",
"preferredTime": "Weekday mornings",
"estimateLow": 1500,
"estimateHigh": 2025,
"smsConsent": false,
"smsConsentText": null,
"utm": {
"utm_source": "google",
"utm_medium": "cpc",
"utm_campaign": "sample-guards",
"gclid": "sample-click",
"referrer": "https://example.com/gutter-guards"
},
"property": {
"source": "rentcast",
"stories": 1,
"yearBuilt": 1998,
"propertyType": "single_family"
},
"receivedAt": "2026-09-25T16:42:07.000Z",
"firstName": "Jordan",
"lastName": "Example",
"street": "412 Sample Ridge Ct",
"city": "Roseville",
"state": "CA",
"zip": "95661"
}| Field | Type | What it holds |
|---|---|---|
| leadId | string or null | The lead's ID in Measured Bid. Null only if the lead could not be saved; the rest still arrives. |
| brand | string | Your widget's ID. Each widget has its own webhook, so one account can feed several CRMs. |
| brandName | string | The business name shown on the widget. |
| service | "gutters" | "painting" | "siding" | "roofing" | "lighting" | "holiday" | "washing" | The trade the widget prices. |
| guardProduct | object | The guard product id and name saved with the estimate, when a named guard was quoted. |
| quoteId | string | The estimate record behind the lead, when there is one. |
| formattedAddress | string | The address as Google formats it: street, city, state and ZIP, then country. |
| name | string | The homeowner's name as typed. |
| phone | string | Their phone number as typed. Every lead has one. |
| string | Optional. Missing when they left it blank. | |
| preferredTime | string | Optional. The best time for a visit, in their words. |
| estimateLow | number | The low end of the price range they saw, in dollars. Missing when no price was shown. |
| estimateHigh | number | The high end of the range, in dollars. Missing when no price was shown. |
| smsConsent | boolean | True only when they checked the box to get texts. |
| smsConsentText | string or null | The exact consent wording they agreed to, or null. |
| utm | object | Where the lead came from. Any of utm_source, utm_medium, utm_campaign, utm_term, utm_content, gclid, gbraid, wbraid, fbclid, msclkid, plus referrer, the page the widget was on. Missing when there's nothing to report. |
| property | object | County records for the home, such as stories, living area and year built. Only on plans with county records, and only when the county has a record. |
| receivedAt | string | When Measured Bid received the lead, as an ISO 8601 time in UTC. |
| firstName | string | The first word of name, for CRMs that want first and last names. |
| lastName | string | Every word of name after the first. Missing when they typed one word. |
| street | string | The street line of formattedAddress, with any unit. The whole address when it isn't a US street address. |
| city | string | The city from formattedAddress. Missing when the address isn't a US street address. |
| state | string | The two-letter state. Missing when the address isn't a US street address. |
| zip | string | The ZIP code. Missing when the address isn't a US street address. |
The new-lead webhook is one way. Form leads can use separate status updates.
The new-lead webhook does not bring HighLevel changes back. Leads your HighLevel forms send to a widget's form leads URL with an external_id can sync stage and price both ways. See custom integrations.
If HighLevel doesn't answer within 8 seconds, the post isn't retried. The lead is still in your dashboard.
Run lengths, wall area and roof squares stay in Measured Bid. Link your team to the lead there when they need them.
Not yet. Leads reach HighLevel through a webhook and a workflow you build once. The steps on this page are the whole setup.
HighLevel lists it as a premium trigger. Each sub-account gets 100 free executions, then HighLevel charges per execution. Check HighLevel's help center for the current rate.
Yes. Every widget has its own webhook address, so an agency can point each client's widget at that client's sub-account. Multi-market includes unlimited widgets.
Not through the webhook. HighLevel gets the contact details, the price range, the trade and the ad source. The measurements are on the lead in your Measured Bid dashboard and in the new-lead email.
Yes. Paste the website code from your widget's Install page into a custom code element on the page, and add that site's address under Websites in the widget's settings.
Start a trial, set your rates and paste your workflow's webhook URL. 14 days or 25 estimates free, no card.