Before using this guide, we recommend reviewing the following sections to understand BlockMark’s webhook system:
This guide provides a step-by-step process for setting up and managing webhooks in BlockMark Registry, enabling your application to receive real-time notifications for events such as certificate issuance and updates. It covers creating a webhook group, verifying an endpoint, handling webhook events, and verifying request authenticity using the webhook secret. The examples use Node.js with Express to demonstrate a simple implementation.
Organisation Settings page..env file). You can retrieve this from the Webhooks section of the Organisation Settings page.Webhooks section within the Organisation Settings page in the Registry dashboard.Create a New Webhook button to open the webhook creation form.issued_certificate.created and issued_certificate.updated).After creating the webhook group, BlockMark Registry requires endpoint verification to ensure the URL is accessible and correctly configured.
event key set to endpoint.verify and a secret string, as shown below:{
"event": "endpoint.verify",
"secret": "abc123"
}
secret string in the response body and an HTTP 200 status code.Verify Now when ready.Below is an example that handles the endpoint.verify event in a Node.js app using Express:
const express = require('express');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
const { event, secret } = req.body;
if (event === 'endpoint.verify') {
return res.status(200).send(secret);
}
return res.status(200).send({ message: 'Webhook received' });
});
app.listen(3000, () => console.log('Server running on port 3000'));
This code checks for the endpoint.verify event and responds with the provided secret. Once verified, your endpoint is ready to receive webhook events.
To process webhook events securely, your application must verify the X-Token header in each request using the webhook secret. The webhook payload always includes an event key (e.g., issued_certificate.created) and a data key containing event-specific details. Below is an enhanced example that handles issued_certificate.created and issued_certificate.updated events, including X-Token verification.
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
app.post('/webhook', (req, res) => {
const { headers, body } = req;
const { event, data } = body;
// Verify X-Token
const xToken = headers['x-token'];
const webhookSecret = process.env.WEBHOOK_SECRET;
const generatedHex = crypto.createHmac('sha256', webhookSecret).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(generatedHex, 'hex'), Buffer.from(xToken, 'hex'))) {
return res.status(400).send({ message: 'Invalid X-Token' });
}
// Handle endpoint verification
if (event === 'endpoint.verify') {
return res.status(200).send(body.secret);
}
// Handle issued_certificate.created
if (event === 'issued_certificate.created') {
console.log('Certificate issued:', data);
return res.status(200).send({ message: 'Certificate creation processed' });
}
// Handle issued_certificate.updated
if (event === 'issued_certificate.updated') {
console.log('Certificate updated:', data);
return res.status(200).send({ message: 'Certificate update processed' });
}
return res.status(200).send({ message: 'Webhook received' });
});
app.listen(3000, () => console.log('Server running on port 3000'));
X-Token header is verified by generating an HMAC using the webhook secret then converting it to a hexadecimal string, and then comparing it with the provided x-token using crypto.timingSafeEqual to prevent timing attacks.endpoint.verify, issued_certificate.created, and issued_certificate.updated events, logging data and responding appropriately.process.env.WEBHOOK_SECRET (e.g., in a .env file).To ensure your endpoint handles webhooks correctly, use the Send Test Webhook feature in the webhook group’s action menu. This sends mock data to your endpoint without incurring costs (unlike non-test webhooks, which cost 10 credits per successful attempt). Test each event type to validate your implementation.
issued_certificate.createdSend Test Webhook and choose issued_certificate.created.{
"event": "issued_certificate.created",
"data": {
"slug": "2db008cf-1ce0-48d8-9b66-300423891fe5",
"name_on_certificate": "William Mcfarland",
"has_name_mismatch": true,
"is_issued_to_thing": false,
"start_time": "1985-10-14T18:17:46.183395+01:00",
"finish_time": "2006-10-05T04:53:52.001364+01:00",
"timestamp": "1972-11-10T03:28:14.717931Z",
"status": "Expired",
"hidden": false,
"is_test": true,
"is_archived": false,
"is_adopted": null,
"bespoke_id": null,
"template": {
"slug": "344f6969-4eed-4632-84aa-d890ef19064f",
"name": "embrace 24/365 partnerships"
},
"is_to_guardian": true,
"is_self_certified": false,
"custom_fields": {},
"custom_notes": {}
}
}
200 status, as shown in the example above.issued_certificate.updatedissued_certificate.updated in the Send Test Webhook menu.{
"event": "issued_certificate.created",
"data": {
"slug": "2db008cf-1ce0-48d8-9b66-300423891fe5",
"name_on_certificate": "William Mcfarland",
"has_name_mismatch": true,
"is_issued_to_thing": false,
"start_time": "1985-10-14T18:17:46.183395+01:00",
"finish_time": "2006-10-05T04:53:52.001364+01:00",
"timestamp": "1972-11-10T03:28:14.717931Z",
"status": "Expired",
"hidden": false,
"is_test": true,
"is_archived": false,
"is_adopted": null,
"bespoke_id": null,
"template": {
"slug": "344f6969-4eed-4632-84aa-d890ef19064f",
"name": "embrace 24/365 partnerships"
},
"is_to_guardian": true,
"is_self_certified": false,
"custom_fields": {},
"custom_notes": {}
}
}
Congratulations, you are now up and running and can start receiving webhooks from BlockMark Registry on your external app.
For additional support, as always, contact us via the help link in the footer.