Elite feature

Webhook Integration

Leads by Alex fires a signed HTTP POST to your endpoint every time a new lead is added. Connect to Zapier, Make, HubSpot, Follow Up Boss, or any custom system — no polling required.

Real-time

Payload delivered within seconds of lead insertion.

Signed

HMAC-SHA256 signature on every request. Verify authenticity server-side.

Any URL

Works with Zapier, Make, n8n, or your own server.

Overview

When a new lead matches your subscription and is inserted into the database, Leads by Alex sends a POST request to every active endpoint you have configured.

Each request contains a JSON body (the payload) and an X-Webhook-Signature header you can use to verify the request came from us.

You can optionally attach a filter to an endpoint so it only fires for leads that match specific counties or lead types (probate, divorce, foreclosure, eviction).

If you enable auto-skiptrace on a saved filter, any matching lead will be automatically skiptraced before the webhook fires — phone numbers and email addresses will be included in the data object. Skiptrace credits are consumed per enriched lead.

Payload schema

All requests use Content-Type: application/json.

JSON example
{
  "event":     "lead.created",
  "timestamp": 1740000000000,
  "data": {
    "id":               12345,
    "case_number":      "2026PR000031",
    "lead_type":        "probate",
    "county":           "Brown",
    "state":            "WI",
    "owner_name":       "John Smith",
    "property_address": "123 Main St, Green Bay, WI 54301",
    "mailing_address":  "456 Oak Ave, Green Bay, WI 54301",
    "filing_date":      "2026-02-01",
    "status":           "new",
    "created_at":       "2026-02-01T12:00:00.000Z",

    // Present only when a matching auto-skiptrace filter fired:
    "primary_phone":    "(920) 555-0100",
    "mobile_1":         "(920) 555-0101",
    "mobile_2":         null,
    "landline_1":       null,
    "email_1":          "john.smith@example.com",
    "email_2":          null
  }
}
FieldTypeDescription
eventstringAlways lead.created
timestampnumberUnix milliseconds when the event was generated
data.idnumberInternal lead ID
data.case_numberstringWCCA case number, e.g. 2026PR000031
data.lead_typestringOne of: probate, divorce, foreclosure, eviction
data.countystringWisconsin county name, e.g. Brown
data.statestringAlways WI (Wisconsin)
data.owner_namestringPrimary party name (owner, decedent, defendant, etc.)
data.property_addressstringProperty or associated address
data.mailing_addressstring | nullMailing address if different from property
data.filing_datestringWCCA filing date in YYYY-MM-DD format
data.statusstringAlways new on creation
data.created_atstringISO-8601 timestamp when the lead was inserted
data.primary_phonestring | nullPhone number — included when an auto-skiptrace filter matched. null if not found or skiptrace not triggered.
data.mobile_1 … mobile_5string | nullAdditional mobile numbers from skiptrace, if available
data.landline_1 … landline_3string | nullLandline numbers from skiptrace, if available
data.email_1 … email_5string | nullEmail addresses from skiptrace, if available

Signature verification

Always verify the signature before processing a webhook. This prevents attackers from forging requests to your endpoint.

Every request includes an X-Webhook-Signature header:

Header
X-Webhook-Signature: t=1740000000000,v1=a3f2...c9d1

The signature is constructed as:

  1. Extract t (timestamp in ms) and v1 (HMAC) from the header.
  2. Build the signed string: ${t}.${rawBody}(timestamp, literal dot, raw JSON body — no newlines or extra whitespace).
  3. Compute HMAC-SHA256(secret, signedString) and compare to v1 using a constant-time equality function.
  4. Optionally reject payloads where |now - t| > 300_000 ms (5 minutes) to prevent replay attacks.

Your per-endpoint secret is shown in the Automations dashboard. Treat it like a password — never expose it client-side.

Code examples

Node.js / TypeScript

TypeScript
import crypto from "crypto";

export function verifyWebhookSignature(
  rawBody: string,
  signature: string,  // from X-Webhook-Signature header
  secret: string,
): boolean {
  // Parse "t=<ms>,v1=<hmac>"
  const parts = Object.fromEntries(
    signature.split(",").map((p) => p.split("=", 2))
  );
  const timestamp = parts["t"];
  const hmac      = parts["v1"];
  if (!timestamp || !hmac) return false;

  // Reject replays older than 5 minutes
  if (Date.now() - Number(timestamp) > 5 * 60 * 1000) return false;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  return crypto.timingSafeEqual(
    Buffer.from(hmac),
    Buffer.from(expected),
  );
}

Python

Python
import hmac
import hashlib
import time

def verify_webhook_signature(raw_body: bytes, signature: str, secret: str) -> bool:
    """Verify the X-Webhook-Signature header from Leads by Alex."""
    # Parse "t=<ms>,v1=<hmac>"
    parts = dict(p.split("=", 1) for p in signature.split(",") if "=" in p)
    timestamp = parts.get("t")
    received_hmac = parts.get("v1")
    if not timestamp or not received_hmac:
        return False

    # Reject replays older than 5 minutes
    if abs(time.time() * 1000 - int(timestamp)) > 5 * 60 * 1000:
        return False

    signed_payload = f"{timestamp}.{raw_body.decode('utf-8')}"
    expected = hmac.new(
        secret.encode("utf-8"),
        signed_payload.encode("utf-8"),
        hashlib.sha256,
    ).hexdigest()

    return hmac.compare_digest(received_hmac, expected)

PHP

PHP
<?php
function verifyWebhookSignature(
    string $rawBody,
    string $signature,
    string $secret
): bool {
    // Parse "t=<ms>,v1=<hmac>"
    $parts = [];
    foreach (explode(',', $signature) as $part) {
        [$k, $v] = explode('=', $part, 2);
        $parts[$k] = $v;
    }
    if (empty($parts['t']) || empty($parts['v1'])) return false;

    // Reject replays older than 5 minutes
    if (abs(microtime(true) * 1000 - (int)$parts['t']) > 5 * 60 * 1000) {
        return false;
    }

    $expected = hash_hmac('sha256', $parts['t'] . '.' . $rawBody, $secret);
    return hash_equals($expected, $parts['v1']);
}

Integrations

ZapierWorks today

Use the "Webhooks by Zapier" trigger (Catch Hook). Requires Zapier Professional or higher.

Make (Integromat)Works today

Use a "Webhooks" module as the trigger in any Make scenario.

n8nWorks today

Add a "Webhook" node as your workflow trigger.

Follow Up BossVia Zapier

Connect via Zapier: Leads by Alex webhook → FUB Create Person action.

HubSpotVia Zapier/Make

Create contacts or deals in HubSpot from every new lead.

Custom serverAny language

Any HTTPS endpoint works. See the code examples above for signature verification.

Zapier quick-start

Guide (comments only)
// In Zapier: use a "Webhooks by Zapier" trigger (Catch Hook)
// 1. Create a new Zap → Trigger: Webhooks by Zapier → Event: Catch Hook
// 2. Copy the webhook URL Zapier gives you
// 3. Paste it into Leads by Alex → Automations → Add endpoint
// 4. Click "Test" to send a sample payload
// 5. Zapier will detect the fields automatically
//
// The payload's "data" object fields will be available as variables
// in all subsequent Zapier steps.

Best practices

  • Respond quickly

    Return HTTP 200 within 10 seconds. Leads by Alex will retry once after 2 seconds on failure. If your processing takes longer, queue the payload and process it asynchronously.

  • Verify signatures

    Always verify the X-Webhook-Signature before processing. Reject requests with an invalid or missing signature.

  • Guard against replays

    Reject payloads where |now - timestamp| > 300 000 ms (5 minutes). Store processed event timestamps or IDs to deduplicate retries.

  • Use HTTPS endpoints only

    HTTP URLs are rejected at save time. Use a valid TLS certificate — self-signed certificates are not accepted.

  • Test before going live

    Each endpoint has a "Test" button in the Automations dashboard that sends a synthetic lead.created payload. Confirm delivery before relying on live data.

  • Keep your secret safe

    Treat your webhook secret like a password. Rotate it by editing the endpoint. Never log or expose it in client-side code.

Ready to connect?

Add your first endpoint in the Automations dashboard. Use the Test button to verify delivery instantly.

Configure endpoints →