Receiving webhooks
Create an endpoint, verify each delivery and handle typed events.
Webhooks tell your server when something happens in Swarmhit: a lead replied, an invitation was accepted, a sender was paused. The SDK creates endpoints and checks that each delivery really comes from Swarmhit. The Webhooks guide lists every event and how deliveries are retried.
Create an endpoint
const webhook = await swarmhit.webhooks.create({
url: 'https://example.com/hooks/swarmhit',
events: ['message.received', 'connection.accepted', 'campaign.finished'],
});
console.log(webhook.secret); // whsec_… store it as SWARMHIT_WEBHOOK_SECRETThe URL must be reachable from the public internet. Use HTTPS. To send a test delivery, call
swarmhit.webhooks.test(webhook.id).
Verify every delivery
Anyone can send a request to your URL, so check its signature before you
trust it. swarmhit.webhooks.unwrap verifies the delivery and returns the
parsed event. It throws a WebhookVerificationError if the signature is
missing or wrong.
The signature is the X-Swarmhit-Signature header: an HMAC-SHA256 hex digest
of the raw body, keyed by the endpoint's signing secret (the whole whsec_…
string).
Verify the raw body, exactly as it arrived. If a framework has already parsed the JSON, the bytes have changed and the signature will not match.
import express from 'express';
import Swarmhit from '@swarmhit/swarmhit-sdk';
const swarmhit = new Swarmhit();
const app = express();
// express.raw keeps the body as bytes for this route.
app.post('/hooks/swarmhit', express.raw({ type: 'application/json' }), async (req, res) => {
let event;
try {
event = await swarmhit.webhooks.unwrap(req.body, req.headers, {
secret: process.env.SWARMHIT_WEBHOOK_SECRET!,
});
} catch {
return res.sendStatus(400);
}
if (event.event === 'message.received') {
console.log(`${event.data.from.firstName} replied: ${event.data.message.text}`);
}
res.sendStatus(200);
});Answer with a 2xx quickly, and do slow work in the background. Delivery is
at-least-once: Swarmhit retries a delivery that fails or times out, so the
same event may reach you twice. Each delivery has a stable id in its
X-Swarmhit-Delivery header. Store the ids you have handled, to skip
duplicates.
The signature carries no timestamp, so it can't tell a replayed delivery from
a new one: deduplicating on X-Swarmhit-Delivery covers that too.
Typed events
unwrap returns a WebhookEvent: a union of every event type. Checking
event.event narrows it, so event.data has the right fields for that event:
import type { WebhookEvent } from '@swarmhit/swarmhit-sdk';
function handle(event: WebhookEvent) {
switch (event.event) {
case 'message.received':
return saveReply(event.data.leadId, event.data.message.text);
case 'campaign.finished':
return notifyTeam(event.data.campaignId);
default:
return; // an event you don't handle, or one added later
}
}To check a signature without parsing the body, use
swarmhit.webhooks.verify(…), or verifyWebhook from @swarmhit/swarmhit-sdk/webhooks.
It takes the same arguments and throws on failure.