Skip to main content

Webhook verification

Import from the dedicated entry point — no client or credentials required:

import {
constructEvent,
verifyWebhookSignature,
SignatureVerificationError,
} from '@minetech/node/webhooks';

constructEvent

Verifies, then parses:

const event = await constructEvent({
payload: req.body, // RAW bytes
signatureHeader: req.header('x-mt-signature'),
secret: process.env.MINETECH_WEBHOOK_SECRET!,
});

verifyWebhookSignature

When you want to parse yourself:

await verifyWebhookSignature({
payload: rawBody,
signatureHeader: header,
secret,
toleranceSeconds: 300, // default
algorithms: ['sha256', 'sha512'],
});

Returns true or throws. Both algorithms are accepted by default, so an endpoint configured for sha512 verifies with no caller change.

Failure reasons

SignatureVerificationError.reason is one of:

ReasonMeaning
no_signaturesHeader absent
malformed_headerNot t=…,v1=…
timestamp_out_of_toleranceOutside the window — check your clock
no_matchDigest mismatch — wrong secret, or not the raw body

These are distinguished deliberately: a clock problem and a wrong secret need different fixes.

Raw body

The digest covers the exact bytes sent. Use express.raw({ type: 'application/json' }) on the webhook route, or request.get_data() in Flask. A parsed-and-re-serialised body will never verify.

Typed events

switch (event.type) {
case 'safety.incident.reported':
console.log(event.data);
break;
default:
// Unknown types parse fine — new events never break a deployed receiver.
break;
}