Lead Capture Webhook

Capture leads from any source — landing pages, forms, chatbots, third-party tools — and get notified in real-time when new contacts arrive.

Prerequisites

  • A Rex account with an API key
  • A server or webhook receiver (e.g., webhook.site for testing)

1. Send a lead to the capture endpoint

The /capture endpoint accepts unauthenticated POST requests (designed for client-side forms and third-party tools):

curl -X POST "https://acme.rexgtm.com/capture" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "source": "organic",
    "metadata": {
      "utm_source": "google",
      "utm_campaign": "spring-launch",
      "landing_page": "/pricing"
    }
  }'

Expected response:

{
  "data": {
    "id": "cont_01HQ...",
    "email": "jane@example.com",
    "first_name": "Jane",
    "last_name": "Doe",
    "stage": "lead",
    "source": "organic",
    "created_at": "2026-03-16T12:00:00Z"
  }
}

The contact is created (or updated if the email already exists) and an event is emitted.

2. Create a webhook subscription

Subscribe to contact.created events to get notified when new leads arrive:

curl -X POST "$REX_URL/webhooks" \
  -H "X-Api-Key: $REX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-server.com/webhooks/rex",
    "events": ["contact.created"],
    "secret": "whsec_your_signing_secret"
  }'

3. Receive and verify the webhook

When a new contact is captured, Rex sends a POST to your URL:

{
  "event": "contact.created",
  "timestamp": "2026-03-16T12:00:01Z",
  "data": {
    "id": "cont_01HQ...",
    "email": "jane@example.com",
    "first_name": "Jane",
    "stage": "lead",
    "source": "organic"
  }
}

The request includes an X-Rex-Signature header for verification:

X-Rex-Signature: t=1710590400,v1=5257a869e7eceb...

Verify in Node.js

import crypto from "crypto";

function verifyWebhook(payload, signature, secret) {
  const [tPart, vPart] = signature.split(",");
  const timestamp = tPart.replace("t=", "");
  const expected = vPart.replace("v1=", "");

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

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

Verify in Python

import hmac, hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in signature.split(","))
    timestamp = parts["t"]
    expected = parts["v1"]

    signed = hmac.new(
        secret.encode(),
        f"{timestamp}.".encode() + payload,
        hashlib.sha256,
    ).hexdigest()

    return hmac.compare_digest(signed, expected)

What's next?

Was this page helpful?

·