webhook Integration · Webhooks

Send your leads anywhere with a signed webhook

Paste a URL from Zapier, Make, n8n or your own server. LeadWebia posts the leads you send as JSON and signs every request with HMAC-SHA256, so you can check it came from us.

Included in every paid plan · from $9 a month

What it does

  • One POST per batch of up to 100 leads; every batch of a send shares a delivery_id. With "One lead per request" on, one POST per lead instead.
  • X-LeadWebia-Signature: sha256=<HMAC of the raw body with your signing secret>.
  • Retries on network errors, 5xx and 429; a "Send test" button posts a sample lead.
  • HTTPS to public hosts only.

Zapier: Catch Hook

  1. Create the trigger

    In a new Zap, choose Webhooks by Zapier → Catch Hook and copy the webhook URL from the Test tab. Webhooks by Zapier needs a paid Zapier plan.

  2. Save the URL in LeadWebia

    Open Integrations → Webhook, paste the URL and click "Save". Copy the signing secret: it's shown only once.

    The Webhook card in LeadWebia Integrations with a saved URL and its signing secret
  3. Test and loop over the leads

    Click "Send test" in LeadWebia, then "Test trigger" in Zapier. To act on each lead, add Looping by Zapier → Create Loop From Line Items over the leads (Professional plan or higher).

Make: Custom webhook

  1. Create the webhook

    Add the Webhooks → Custom webhook trigger, create a webhook and copy its address.

  2. Save it in LeadWebia and send a test

    Paste the address in Integrations → Webhook, click "Save" and then "Send test": Make learns the data structure from that request.

  3. Iterate over the leads

    Add an Iterator on the leads list so each lead becomes its own bundle for the next modules (a CRM, a sheet, Slack…).

Send leads

  1. From the Dashboard

    Select leads, open Actions → Send to… → Webhook and click "Send". Sends of more than 100 leads run in the background and you're told when they finish.

    The Send to webhook dialog in the LeadWebia Dashboard

How the requests look

Method and bodyPOST, Content-Type: application/json (UTF-8)
Eventsleads.sent (your sends) and test ("Send test", one sample lead)
HeadersX-LeadWebia-Event, X-LeadWebia-Timestamp (Unix seconds), X-LeadWebia-Signature, User-Agent: LeadWebia-Webhook/1.0
Signaturesha256= + hex HMAC-SHA256 of the raw body, keyed with your signing secret (whsec_…)
BatchesUp to 100 leads per request in "leads" (event leads.sent), or one lead per request in "lead" plus its first "email" (event lead.sent, setting "One lead per request"); batch.index / batch.count and one delivery_id per send
RetriesNetwork errors, 5xx and 429: 3 more tries after 1, 2 and 4 seconds (429 honours Retry-After up to 30 s). Other 4xx and redirects aren't retried; a batch that fails for good stops the send.
Timeout10 seconds per request
URLshttps:// only, to a public host (private and internal addresses are refused)

The payload

Each lead in "leads" carries these fields; null when there is nothing to put there.

DataFieldsWhat it is
Businessname, categoryThe name and the Google Maps category, e.g. "Roofing contractor".
Addressvicinity, city, state, postal_codeThe full address, plus city, state and ZIP code in their own columns for US addresses.
Phonephone, phone_e164As listed on Maps, and in E.164 format (+15125550134) for dialers and CRMs.
WebsitewebsiteThe website on the listing; empty when the business has none.
Reputationrating, user_ratings_totalGoogle rating and number of reviews.
EmailsemailsFound on the business's website and public pages. Maps listings don't include emails.
Social profilesfacebook, instagram, linkedin, twitter, tiktok, youtubeLinks to the profiles the business publishes.
PageSpeed (mobile)performance, accessibility, best_practices, seoGoogle PageSpeed scores, 0–100, for businesses with their own site.
Techcms, adsThe CMS (WordPress, Wix, Squarespace…) and the ad pixels found on the site.
Lead scorescore, score_label0–100 and hot / warm / cold, from no website, slow or broken site, no SSL, ads and an unclaimed profile.
Links and pipelinegoogle_maps_url, place_id, niche, status, saved_atThe Maps listing, Google's place ID, the niche it was found for, your status and when you saved it.

Payload and signature

Example body

{
  "event": "leads.sent",
  "sent_at": "2026-10-13T15:04:05Z",
  "source": "leadwebia",
  "delivery_id": "6f1c2a9e-0d4b-4c6e-9a51-2b7e8c1f3d20",
  "batch": { "index": 1, "count": 1 },
  "leads": [
    {
      "place_id": "ChIJ…",
      "name": "Joe's Pizza",
      "status": "Contacted",
      "score": 78,
      "score_label": "hot",
      "category": "Pizza restaurant",
      "vicinity": "1200 Congress Ave, Austin, TX 78701",
      "city": "Austin",
      "state": "TX",
      "postal_code": "78701",
      "rating": 4.6,
      "user_ratings_total": 212,
      "website": null,
      "phone": "+1 512-555-0134",
      "phone_e164": "+15125550134",
      "emails": ["hello@joespizza.com"],
      "facebook": "https://www.facebook.com/joespizza",
      "instagram": null, "linkedin": null, "twitter": null, "tiktok": null, "youtube": null,
      "performance": null, "accessibility": null, "best_practices": null, "seo": null,
      "cms": null,
      "ads": [],
      "niche": "pizza",
      "google_maps_url": "https://www.google.com/maps/place/?q=place_id:ChIJ…",
      "landing_page_url": null,
      "leadwebia_url": "https://leadwebia.com/dashboard?q=Joe%27s+Pizza&websiteFilter=all",
      "saved_at": "2026-10-12T18:30:00Z"
    }
  ]
}

Verify the signature in Node.js

// Express: keep the raw body, the signature is computed over its exact bytes.
const crypto = require('crypto');
const express = require('express');
const app = express();

app.post('/leadwebia', express.raw({ type: 'application/json' }), (req, res) => {
  const header = req.get('X-LeadWebia-Signature') || '';
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.LEADWEBIA_SIGNING_SECRET)
    .update(req.body)                       // Buffer with the raw body
    .digest('hex');
  const valid = header.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
  if (!valid) return res.sendStatus(401);

  const payload = JSON.parse(req.body.toString('utf8'));
  // Optional: refuse old deliveries (replays).
  if (Date.now() - Date.parse(payload.sent_at) > 5 * 60 * 1000) return res.sendStatus(400);

  for (const lead of payload.leads) {
    // lead.place_id, lead.name, lead.phone_e164, lead.emails…
  }
  res.sendStatus(200);
});

Verify the signature in Python

# Flask: request.get_data() is the raw body the signature covers.
import hashlib
import hmac
import os

from flask import Flask, abort, request

app = Flask(__name__)
SECRET = os.environ["LEADWEBIA_SIGNING_SECRET"].encode()


@app.post("/leadwebia")
def leadwebia():
    raw = request.get_data()
    expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, request.headers.get("X-LeadWebia-Signature", "")):
        abort(401)
    payload = request.get_json()
    for lead in payload["leads"]:
        ...  # lead["place_id"], lead["name"], lead["phone_e164"], lead["emails"]…
    return "", 200

Good to know

  • Sends start from the Dashboard; automatic sends after each run exist for Google Sheets only.
  • The signing secret is shown once. Saving the URL again creates a new secret.
  • Answer with a 2xx within 10 seconds; do slow work after answering.
  • Available on paid plans.

Facts about other companies come from their own documentation, checked on October 13, 2026: Zapier: trigger Zaps from webhooks · Zapier: loop your Zap actions · Make: webhooks · Make: Iterator · n8n: Webhook node.

Frequently asked

How do I know a request really comes from LeadWebia?

Compute HMAC-SHA256 of the raw request body with your signing secret, prefix it with "sha256=" and compare it with the X-LeadWebia-Signature header in constant time. The Node and Python snippets above do exactly that.

Can I use n8n or my own server?

Yes: any HTTPS URL on a public host works. In n8n, add a Webhook node with the POST method and use its production URL (n8n registers it when you publish the workflow); the leads are in $json.body.leads.

What if my endpoint is down?

Network errors, 5xx and 429 answers are retried three times (1, 2 and 4 seconds apart). If a batch still fails, the send stops and the Dashboard shows how many leads went through.

Why do I get several requests for one send?

Each request carries up to 100 leads. batch.index and batch.count tell you where you are, and delivery_id is the same for every batch of one send.

Other integrations

Plug qualified local leads into your stack

Start with 50 free leads; webhooks are included in every paid plan.