Capture leads from any source — landing pages, forms, chatbots, third-party tools — and get notified in real-time when new contacts arrive.
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.
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"
}'
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...
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)
);
}
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)