Webhooks for Marketing Automation
A webhook is a push notification between two systems
A webhook is simply an HTTP POST request that one system sends to a URL you configure, the moment something happens on its end — a new form submission in Typeform, a deal stage change in HubSpot, a payment event in Stripe. Instead of your system repeatedly asking 'anything new?' (polling), the source system pushes the event to you the instant it occurs, which is the lightweight, SaaS-era equivalent of the publisher/broker/consumer pattern in full event-driven architecture — without needing dedicated streaming infrastructure like Kafka. Most marketing automation platforms (Zapier, Make, n8n, and native integrations in HubSpot/Salesforce) are built almost entirely on webhooks as their triggering mechanism.
// Minimal webhook receiver: verify signature, check idempotency,
// then process. Most of the real engineering work in a webhook
// receiver is defensive, not business logic.
import crypto from "crypto";
export async function handleStripeWebhook(req: Request): Promise<Response> {
const signature = req.headers.get("stripe-signature") ?? "";
const rawBody = await req.text();
const expectedSig = crypto
.createHmac("sha256", process.env.STRIPE_WEBHOOK_SECRET!)
.update(rawBody)
.digest("hex");
if (signature !== expectedSig) {
return new Response("Invalid signature", { status: 401 });
}
const event = JSON.parse(rawBody);
// Idempotency: Stripe (like most providers) may redeliver the same
// event more than once. Check a processed-events table before acting.
const alreadyProcessed = await checkEventProcessed(event.id);
if (alreadyProcessed) {
return new Response("OK (already processed)", { status: 200 });
}
await processPaymentEvent(event);
await markEventProcessed(event.id);
return new Response("OK", { status: 200 });
}
declare function checkEventProcessed(eventId: string): Promise<boolean>;
declare function markEventProcessed(eventId: string): Promise<void>;
declare function processPaymentEvent(event: any): Promise<void>;Why webhook receivers need to respond fast and process async
Most webhook providers expect a 2xx response within a short timeout window (often 5-30 seconds) and will retry delivery — sometimes aggressively — if that response doesn't arrive in time. A receiver that does slow, synchronous work inside the webhook handler itself (calling three other APIs, running a heavy computation) risks timing out and triggering the provider's retry logic, which then causes the same event to be reprocessed, compounding load and duplicate-processing risk. The standard pattern is to acknowledge receipt immediately (write the raw event to a queue or database) and process the actual business logic asynchronously in a separate worker.
Webhooks vs. polling for integration triggers
| Dimension | Webhooks (push) | Polling (pull) |
|---|---|---|
| Latency | Near-instant | Bounded by poll interval |
| Load on source system | Minimal — only sends when something happens | Constant — repeated requests regardless of new activity |
| Reliability if receiver is down | Depends on provider's retry/redelivery policy | Self-healing — next poll just picks up what's new |
| Setup complexity | Requires a publicly reachable, secured endpoint | Simpler — just an API call on a schedule |
An unsigned, unverified webhook endpoint is an open invitation to spoofed events
No-code automation platforms are webhook orchestrators with a visual layer
What's Next?
Webhooks move individual events between systems in real time; the complementary problem of moving and transforming large volumes of historical and batch data between systems is the domain of dedicated ETL/ELT pipelines feeding into a marketing data warehouse.
I build these systems professionally.
Whether it's a RAG pipeline, analytics migration, or AI workflow — let's talk.