Documentation Index
Fetch the complete documentation index at: https://docs.didx.co.za/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Webhooks are HTTP callbacks that notify your application about important events on the didx:me platform, eliminating the need to continuously poll the API for status updates.
Supported Events
For Issuers
For Verifiers
| Event | Description |
|---|
openid4vc.issuance.offered | Credential offer sent to user |
openid4vc.issuance.completed | User accepted and received the credential |
openid4vc.issuance.failed | Issuance attempt failed |
openid4vc.issuance.expired | Credential offer expired before user accepted |
| Event | Description |
|---|
openid4vc.presentation.requested | Presentation request created |
openid4vc.presentation.verified | User successfully presented credentials |
openid4vc.presentation.failed | Verification attempt failed |
openid4vc.presentation.expired | Presentation request expired |
Registering a Webhook Endpoint
curl -X POST "https://test.didxtech.com/me-creds/api/endpoints" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-domain.com/webhooks/credentials"
}'
Response (201 Created)
{
"data": {
"id": "du398r0fqd",
"url": "https://your-domain.com/webhooks/credentials",
"createdAt": "2025-01-01T00:00:00.000Z",
"updatedAt": "2025-01-01T00:00:00.000Z"
}
}
Webhook Payload Structure
All webhook payloads include an eventType and a payload with a resource reference:
{
"eventType": "openid4vc.issuance.completed",
"payload": {
"openId4VcIssuanceId": "cmfwfjxdq003js601bmgy9tva"
}
}
Technical Requirements
Your webhook endpoint must:
- Accept POST requests
- Use HTTPS exclusively
- Respond promptly with a 2xx status code
- Handle duplicate deliveries (the platform may retry on failure)
- Be idempotent, processing the same event twice should produce the same result
Implementation Example
Here’s a Node.js/Express implementation with deduplication handling and asynchronous processing:
const processedWebhooks = new Set();
const eventQueue = [];
app.post('/webhooks/credentials', async (req, res) => {
try {
const webhookId = req.headers['webhook-id'];
const { eventType, payload } = req.body;
// Deduplicate, the platform may send the same webhook more than once
if (processedWebhooks.has(webhookId)) {
console.log(`Webhook ${webhookId} already processed, skipping`);
return res.status(200).send('OK');
}
const webhookEvent = {
webhookId,
eventType,
payload,
receivedAt: new Date(),
processed: false
};
eventQueue.push(webhookEvent);
processedWebhooks.add(webhookId);
// Respond immediately, then process asynchronously
res.status(200).send('OK');
setImmediate(() => processWebhookAsync(webhookEvent));
} catch (error) {
console.error('Failed to store webhook:', error);
res.status(500).json({ error: 'Failed to process webhook' });
}
});
async function processWebhookAsync(webhookEvent) {
try {
console.log(`Processing webhook ${webhookEvent.webhookId}: ${webhookEvent.eventType}`);
if (webhookEvent.eventType === 'openid4vc.issuance.completed') {
console.log(`Credential issued: ${webhookEvent.payload.openId4VcIssuanceId}`);
// Add your business logic here
}
webhookEvent.processed = true;
} catch (error) {
console.error(`Failed to process webhook ${webhookEvent.webhookId}:`, error);
}
}
Local Development
Use ngrok to expose your local server via a public HTTPS URL during development:
Register the resulting https:// ngrok URL as your webhook endpoint. The platform will retry failed deliveries automatically.