Express
The signature covers the raw body, so the webhook route must read it as bytes, before
any JSON parser runs. express.raw does that for one route.
npm install express ricochet-webhooksimport express from 'express';import { verify, WebhookVerificationError } from 'ricochet-webhooks';
const app = express();const secret = process.env.RICOCHET_WEBHOOK_SECRET;const handled = new Set(); // use your database in production
app.post('/webhooks', express.raw({ type: '*/*' }), (req, res) => { let id; try { ({ id } = verify(req.body, req.headers, secret)); } catch (error) { if (error instanceof WebhookVerificationError) return res.status(401).send(error.reason); throw error; } if (handled.has(id)) return res.sendStatus(200);
const event = JSON.parse(req.body); console.log('received', event.type ?? req.get('x-github-event')); handled.add(id); res.sendStatus(200);});
app.listen(3000);req.body is a Buffer and req.headers is passed as is. Answer 2xx once the event
is handled; any 5xx makes Ricochet retry it.
If the app registers express.json() globally, register the webhook route before it,
or the body arrives parsed and the signature no longer matches.
Try it locally
Section titled “Try it locally”node server.jsricochet listen --forward localhost:3000/webhooksDeliveries through the CLI carry no webhook-signature (a CLI destination has no
signing secret), so turn the check off in local development, for example with an
environment variable. Never skip it just because the header is missing: that would
accept unsigned requests in production too.