Import
import { webhookMiddleware, verifyWebhookSignature, verifyAndParseWebhook } from '@keystoneos/node';
Express Middleware
The easiest way to handle webhooks in Express:
import express from 'express';
import { webhookMiddleware } from '@keystoneos/node';
app.post(
'/webhooks/keystone',
express.raw({ type: 'application/json' }),
webhookMiddleware({ secret: process.env.WEBHOOK_SECRET }),
(req, res) => {
const { event, data } = req.keystoneEvent;
switch (event) {
case 'settlement.state.compliance_cleared':
console.log(`${data.settlement_id}: ${data.from_state} -> ${data.to_state}`);
break;
case 'settlement.state.finalized':
console.log(`Finalized: ${data.settlement_id}`);
break;
case 'settlement.state.rolled_back':
console.log(`Rolled back: ${data.settlement_id}`);
break;
}
res.sendStatus(200);
},
);
You must use express.raw() (not express.json()) so the middleware receives the raw body for signature verification.
Parameters
| Property | Type | Required | Description |
|---|
secret | string | Yes | Your webhook signing secret. |
Behavior
- Reads
X-Keystone-Signature header
- Verifies HMAC-SHA256 signature using timing-safe comparison
- Parses the JSON body
- Attaches parsed event to
req.keystoneEvent
- Returns 401 if signature is invalid or missing
Manual Verification
For non-Express frameworks (Hono, Fastify, serverless), use the lower-level functions:
verifyAndParseWebhook
import { verifyAndParseWebhook } from '@keystoneos/node';
// Hono example
app.post('/webhooks/keystone', async (c) => {
const body = await c.req.text();
const signature = c.req.header('x-keystone-signature');
const event = verifyAndParseWebhook(body, signature, process.env.WEBHOOK_SECRET);
if (!event) {
return c.json({ error: 'Invalid signature' }, 401);
}
// Handle event...
return c.json({ ok: true });
});
| Parameter | Type | Required | Description |
|---|
payload | string | Buffer | Yes | Raw request body. |
signature | string | undefined | Yes | The X-Keystone-Signature header. |
secret | string | Yes | Your webhook signing secret. |
Returns the parsed WebhookEvent or null if verification fails.
verifyWebhookSignature
Signature verification only, without JSON parsing:
import { verifyWebhookSignature } from '@keystoneos/node';
const isValid = verifyWebhookSignature(rawBody, signature, secret);
Returns true if the signature is valid.
WebhookEvent Type
interface WebhookEvent {
event: string;
data: Record<string, unknown>;
}
Common Events
| Event | Description |
|---|
settlement.state.* | Any settlement state change (use wildcard pattern). |
settlement.state.finalized | Settlement completed successfully. |
settlement.state.rolled_back | Settlement rolled back. |
compliance.cleared | All parties passed compliance. |
compliance.flagged | A party was flagged for manual review. |
test.ping | Test event from webhook endpoint testing. |