import crypto from 'node:crypto';
import express from 'express';
const app = express();
function sign(body) {
return `sha256=${crypto
.createHmac('sha256', process.env.CLAY_WEBHOOK_SIGNING_SECRET)
.update(body, 'utf8')
.digest('hex')}`;
}
function signaturesMatch(actual, expected) {
const actualBuffer = Buffer.from(actual);
const expectedBuffer = Buffer.from(expected);
return actualBuffer.length === expectedBuffer.length && crypto.timingSafeEqual(actualBuffer, expectedBuffer);
}
async function fetchRunResults(routineRunId) {
// For batch routine runs, use `/public/v0/routines/run-batch/${routineRunId}/results`.
const result = await fetch(`https://api.clay.com/public/v0/routines/run/${routineRunId}/results`, {
headers: { 'clay-api-key': process.env.CLAY_API_KEY },
});
return result.json();
}
app.post('/hooks/clay', express.raw({ type: 'application/json' }), async (req, res) => {
const body = req.body.toString('utf8');
const actualSignature = req.get('X-Clay-Signature') ?? '';
const expectedSignature = sign(body);
if (!signaturesMatch(actualSignature, expectedSignature)) {
return res.sendStatus(401);
}
const event = JSON.parse(body);
const routineRunId = event.data.routine_run_id;
const run = await fetchRunResults(routineRunId);
return res.sendStatus(204);
});