Docs › Integrations

Webhook payload reference

Every field we send when a lead is submitted or verified, and how to consume it from your own endpoint.

When a visitor asks your team to follow up or verifies contact to receive a generated Design Vision, we send a POST with a JSON body to any HTTPS URL you configure. That's what powers the Zapier integration, and it works just as well pointed at Make, n8n, Pipedream, or an endpoint you wrote yourself.

When we send it

One request per lead and event, per integration. lead.submitted fires immediately when a visitor without a photo (or outside the service area) provides contact information. lead.verified fires after an in-market visitor generates a design, verifies contact, and the Design Vision finishes rendering (or definitively fails to render).

Example payload

This is generated live from the same code that builds real deliveries, so it's always current. A test event looks identical except that test is true.

{
  "id": "f8706305-ac63-43d2-b947-4bc2fb1e0345",
  "event": "lead.verified",
  "version": "2026-08-19",
  "occurred_at": "2026-09-26T15:20:12Z",
  "test": true,
  "account": {
    "id": 42,
    "name": "Green Valley Landscaping"
  },
  "lead": {
    "id": "cb69a392-f4fe-4099-8192-edfd9ec06041",
    "lead_type": "verified",
    "email": "homeowner@example.com",
    "phone": "+19135551234",
    "contact_channel": "email",
    "submitted_at": "2026-09-26T15:20:12Z",
    "verified_channel": "email",
    "verified_at": "2026-09-26T15:20:12Z",
    "address": "123 Sample Street, Lawrence, KS 66044",
    "latitude": 38.9717,
    "longitude": -95.2353,
    "in_service_area": true,
    "project_type": "Front Yard",
    "service_area": "Front Yard",
    "source": "widget",
    "source_page_url": "https://example.com/services/landscape-design",
    "style": "Modern Prairie",
    "budget": "$10,000 - $25,000",
    "goals": "Curb appeal, Low maintenance",
    "goals_list": [
      "Curb appeal",
      "Low maintenance"
    ],
    "features": "Paver walkway, Landscape lighting",
    "features_list": [
      "Paver walkway",
      "Landscape lighting"
    ],
    "offered_features": "Paver walkway, Landscape lighting, Native bed conversion",
    "offered_features_list": [
      "Paver walkway",
      "Landscape lighting",
      "Native bed conversion"
    ],
    "recommended_features": "Native bed conversion",
    "recommended_features_list": [
      "Native bed conversion"
    ],
    "feedback": "Would love more color in spring.",
    "highlights": "Strong entry framing; Layered plantings",
    "considerations": "Irrigation for the new bed"
  },
  "media": {
    "before_photo_url": "https://curbsight.ai/assets/sample_design_concept.jpg",
    "concept_image_url": "https://curbsight.ai/assets/sample_design_concept.jpg",
    "design_vision_pdf_url": "https://curbsight.ai/assets/sample_design_concept.jpg",
    "design_vision_pdf_status": "ready",
    "design_vision_download_url": "https://curbsight.ai/d/sample1234"
  }
}

Fields

A key is never omitted — if we don't have a value it arrives as null. That's deliberate: tools like Zapier build their field list from the first payload they see, so a disappearing key would become permanently unmappable.

Top level

FieldNotes
idUnique per delivery. Use this to guard against duplicates.
eventlead.submitted or lead.verified.
versionPayload version. We add fields freely; we don't rename or remove without bumping this.
occurred_atWhen the lead was submitted or verified, ISO 8601 UTC. Order on this, not on arrival time.
testtrue for a Send test event delivery, false for a real lead.
accountYour CurbSight account id and business name.

lead

FieldNotes
idStable id for this lead. The same lead always has the same one.
lead_typesubmitted or verified.
email, phoneWhichever contact destination they gave.
contact_channelemail or sms.
submitted_atWhen contact was submitted, ISO 8601 UTC.
verified_channel, verified_atSet only for lead.verified; otherwise null.
addressThe property address they typed, as typed.
latitude, longitudeNumbers, not strings. null if we couldn't geocode.
in_service_areaBoolean — whether the address falls inside the work radius on your Fern.
project_typeThe Fern project type the visitor chose, e.g. Front Yard.
service_areaThe location classified from the photo, when a photo was accepted.
sourcewidget if they started from the launcher on your site, hosted from a direct link.
source_page_urlThe page of yours they were on. null for hosted chats.
style, budgetWhat they picked, as text.
goals, features, offered_featuresComma-separated strings. Use these in Zapier.
goals_list, features_list, offered_features_listThe same values as arrays, for tools that handle them properly.
recommended_features, recommended_features_listDeprecated compatibility fields; no feature-recommendation model runs.
feedbackAnything they typed in their own words. Truncated at 2,000 characters.
highlights, considerationsNotes from the design critique, joined with semicolons.

media

FieldNotes
before_photo_urlThe photo the visitor uploaded, if any.
concept_image_urlThe generated design concept.
design_vision_pdf_urlThe full Design Vision booklet. null when it isn't available for this lead.
design_vision_pdf_statusready, unavailable, or not_generated for submitted leads.
design_vision_download_urlA short link to a ready booklet, good for 30 days; otherwise null.

Image and PDF links are unguessable but not password-protected, so treat them as sensitive — anyone with the link can open them. They don't expire.

Headers

HeaderValue
Content-Typeapplication/json; charset=utf-8
User-AgentCurbSight-Webhooks/1.0 (+https://curbsight.ai/docs/webhooks)
X-Curbsight-EventThe event name, e.g. lead.verified.
X-Curbsight-Request-IdMatches the body's id. Stable across retries of the same delivery.
X-Curbsight-AttemptWhich attempt this is, 1 through 6.

Zapier's Catch Hook can't map headers, which is why id, event, version, test, and occurred_at also appear in the body.

How to respond

Return any 2xx and we consider it delivered. We don't read the response body beyond logging a short excerpt for you to inspect.

  • 2xx — success.
  • 408, 425, 429, 5xx, timeouts, connection errors — we retry, up to six attempts over roughly seven hours. 429 honours your Retry-After header if it's an hour or less.
  • Everything else, including 3xx and other 4xx — permanent failure, no retry.

We follow no redirects. If your URL redirects, configure the final destination directly. Five consecutive failed leads will pause the integration and tell you why.

Endpoint requirements

  • Must be https:// on the standard port.
  • Must resolve to a public address — we reject anything pointing at private or internal networks.
  • No credentials embedded in the URL.
  • Answer within 10 seconds. If you need to do slow work, acknowledge first and process afterwards.

We check these when you save the integration and again on every delivery, so a URL that changes where it points later will be caught rather than trusted.

Something unclear or out of date? Email support@curbsight.ai.