Payload Examples
This page provides complete, real-world examples of webhook payloads for each event type. Use these examples to understand the data structure and build your webhook handlers.
Request Structure
All webhook notifications are sent as HTTP POST requests with the following characteristics:
HTTP Method: POST Content-Type: application/json Authentication: Configured authentication method (Bearer, Basic Auth, API Key, etc.)
Request Headers Example
POST /webhooks/beedeez HTTP/1.1
Host: api.yourcompany.com
Content-Type: application/json
Authorization: Bearer your-secret-bearer-token
X-Webhook-Source: beedeez
Content-Length: 1234
Certificate Completed Event
Triggered when a user successfully completes a certificate.
Event Type
certificate_completed
Complete Payload Example
{
"_id": "507f1f77bcf86cd799439011",
"_userId": "507f191e810c19729de860ea",
"_ownerId": "507f191e810c19729de860eb",
"_badgeId": "507f191e810c19729de860ec",
"creationDate": "2024-11-27T10:30:00.000Z",
"expires": "2025-11-27T10:30:00.000Z",
"disabled": false,
"expiryReminderSent": false,
"_lessonActiveIds": [
"507f191e810c19729de860ed",
"507f191e810c19729de860ee",
"507f191e810c19729de860ef"
],
"ruleData": {
"type": "certification",
"name": "Safety Training Certificate",
"description": "Complete all safety training modules",
"validityDurationDays": 365
},
"createdAt": "2024-11-27T10:30:00.000Z",
"updatedAt": "2024-11-27T10:30:00.000Z",
"__v": 0
}
Field Descriptions
| Field | Type | Description |
|---|---|---|
_id | ObjectId | Unique identifier for this badge/certificate instance |
_userId | ObjectId | ID of the user who earned the certificate |
_ownerId | ObjectId | ID of the organization/owner |
_badgeId | ObjectId | ID of the badge definition/template |
creationDate | ISO 8601 Date | When the user completed the certificate requirements |
expires | ISO 8601 Date | When the certificate expires (null if no expiration) |
disabled | Boolean | Whether the certificate has been disabled/revoked |
expiryReminderSent | Boolean | Whether an expiry reminder has been sent |
_lessonActiveIds | Array\<ObjectId> | IDs of lesson activities that validated this certificate |
ruleData | Object | Additional data from the badge rule definition |
createdAt | ISO 8601 Date | When this certificate record was created in the database |
updatedAt | ISO 8601 Date | When this certificate record was last updated |
__v | Number | MongoDB version key |
Use Case Example
Scenario: Notify HR system when employee completes safety certification
// Node.js webhook handler
app.post('/webhooks/beedeez/certificates', async (req, res) => {
const certificate = req.body;
if (certificate.ruleData.type === 'certification') {
await hrSystem.updateEmployeeRecord({
employeeId: certificate._userId,
certification: {
name: certificate.ruleData.name,
completedDate: certificate.creationDate,
expiryDate: certificate.expires,
certificateId: certificate._id,
},
});
// Send notification to manager
await notificationService.send({
to: 'manager@company.com',
subject: 'Employee Certification Completed',
body: `Employee completed ${certificate.ruleData.name}`,
});
}
res.status(200).json({ received: true });
});
Certificate Expired Event
Triggered when a certificate reaches its expiration date.
Event Type
certificate_expired
Complete Payload Example
{
"_id": "507f1f77bcf86cd799439011",
"_userId": "507f191e810c19729de860ea",
"_ownerId": "507f191e810c19729de860eb",
"_badgeId": "507f191e810c19729de860ec",
"creationDate": "2023-11-27T10:30:00.000Z",
"expires": "2024-11-27T10:30:00.000Z",
"disabled": false,
"expiryReminderSent": true,
"_lessonActiveIds": ["507f191e810c19729de860ed", "507f191e810c19729de860ee"],
"ruleData": {
"type": "certification",
"name": "First Aid Certification",
"description": "First aid and emergency response training",
"validityDurationDays": 365
},
"createdAt": "2023-11-27T10:30:00.000Z",
"updatedAt": "2024-11-27T10:30:00.000Z",
"__v": 0
}
Field Descriptions
Fields are identical to the certificate_completed event. Key differences:
expiresdate is in the past (certificate has expired)expiryReminderSentis typicallytrue(reminder was sent before expiration)creationDateshows the original completion date (1 year ago in this example)
Use Case Example
Scenario: Trigger re-certification workflow when certificate expires
// Node.js webhook handler
app.post('/webhooks/beedeez/certificates', async (req, res) => {
const certificate = req.body;
// Check if certificate has expired
const now = new Date();
const expiryDate = new Date(certificate.expires);
if (expiryDate < now) {
// Trigger re-certification workflow
await workflowEngine.start({
workflow: 'recertification',
userId: certificate._userId,
certificateId: certificate._badgeId,
certificateName: certificate.ruleData.name,
expiredDate: certificate.expires,
});
// Update compliance tracking
await complianceSystem.markAsExpired({
employeeId: certificate._userId,
certificateId: certificate._id,
requiresRenewal: true,
});
// Send notification to employee and manager
await notificationService.sendExpiredCertificateAlert({
userId: certificate._userId,
certificateName: certificate.ruleData.name,
expiredDate: certificate.expires,
});
}
res.status(200).json({ received: true });
});
Handling Multiple Event Types
If your webhook endpoint handles multiple event types, you can differentiate them using the payload structure or additional metadata.
Example: Multi-Event Handler
app.post('/webhooks/beedeez', async (req, res) => {
const payload = req.body;
// Determine event type based on payload characteristics
const now = new Date();
const expiryDate = payload.expires ? new Date(payload.expires) : null;
let eventType;
if (expiryDate && expiryDate < now) {
eventType = 'certificate_expired';
} else {
eventType = 'certificate_completed';
}
// Route to appropriate handler
switch (eventType) {
case 'certificate_completed':
await handleCertificateCompleted(payload);
break;
case 'certificate_expired':
await handleCertificateExpired(payload);
break;
default:
console.warn('Unknown event type:', eventType);
}
res.status(200).json({ received: true, eventType });
});
async function handleCertificateCompleted(certificate) {
console.log('Certificate completed:', certificate._id);
// Handle completion logic...
}
async function handleCertificateExpired(certificate) {
console.log('Certificate expired:', certificate._id);
// Handle expiration logic...
}
Error Responses
Your webhook endpoint should return appropriate HTTP status codes:
Success Response
HTTP/1.1 200 OK
Content-Type: application/json
{
"received": true,
"message": "Webhook processed successfully",
"eventId": "507f1f77bcf86cd799439011"
}
Error Responses
Authentication Failed:
HTTP/1.1 401 Unauthorized
Content-Type: application/json
{
"error": "Unauthorized",
"message": "Invalid authentication credentials"
}
Invalid Payload:
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Bad Request",
"message": "Invalid payload structure"
}
Internal Server Error:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
{
"error": "Internal Server Error",
"message": "Failed to process webhook"
}
Only return 2xx status codes if the webhook was successfully received and processed. Returning 2xx prevents Beedeez from retrying the delivery.
Idempotency Handling
Since webhooks may be delivered multiple times, implement idempotency:
Example: Idempotent Handler
const processedWebhooks = new Set(); // In production, use a database
app.post('/webhooks/beedeez', async (req, res) => {
const certificate = req.body;
const webhookId = certificate._id;
// Check if already processed
if (processedWebhooks.has(webhookId)) {
console.log('Duplicate webhook, already processed:', webhookId);
return res.status(200).json({
received: true,
duplicate: true,
});
}
try {
// Process webhook
await processCertificate(certificate);
// Mark as processed
processedWebhooks.add(webhookId);
res.status(200).json({ received: true });
} catch (error) {
console.error('Error processing webhook:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
Database-Based Idempotency
// Using a database to track processed webhooks
app.post('/webhooks/beedeez', async (req, res) => {
const certificate = req.body;
const webhookId = certificate._id;
// Check database
const existing = await db.webhookLogs.findOne({ webhookId });
if (existing) {
return res.status(200).json({
received: true,
duplicate: true,
});
}
try {
// Process webhook
await processCertificate(certificate);
// Store in database
await db.webhookLogs.insert({
webhookId,
receivedAt: new Date(),
payload: certificate,
processed: true,
});
res.status(200).json({ received: true });
} catch (error) {
console.error('Error processing webhook:', error);
res.status(500).json({ error: 'Processing failed' });
}
});
Testing Webhooks
Manual Testing with curl
# Test certificate_completed event
curl -X POST https://your-endpoint.com/webhooks/beedeez \
-H "Authorization: Bearer your-token" \
-H "Content-Type: application/json" \
-d '{
"_id": "507f1f77bcf86cd799439011",
"_userId": "507f191e810c19729de860ea",
"_ownerId": "507f191e810c19729de860eb",
"_badgeId": "507f191e810c19729de860ec",
"creationDate": "2024-11-27T10:30:00.000Z",
"expires": "2025-11-27T10:30:00.000Z",
"disabled": false,
"expiryReminderSent": false,
"_lessonActiveIds": ["507f191e810c19729de860ed"],
"ruleData": {
"type": "certification",
"name": "Test Certificate",
"validityDurationDays": 365
},
"createdAt": "2024-11-27T10:30:00.000Z",
"updatedAt": "2024-11-27T10:30:00.000Z"
}'
Testing with Postman
- Create a new POST request
- Set URL to your webhook endpoint
- Add authentication header (Bearer token, API key, etc.)
- Set Content-Type to
application/json - Paste example payload in the body
- Send request and verify response
Complete Integration Example
Here's a complete, production-ready webhook handler:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
// Configuration
const WEBHOOK_TOKEN = process.env.BEEDEEZ_WEBHOOK_TOKEN;
const WEBHOOK_SECRET = process.env.BEEDEEZ_WEBHOOK_SECRET;
// Middleware: Authentication
function authenticateWebhook(req, res, next) {
const authHeader = req.headers.authorization;
if (!authHeader || authHeader !== `Bearer ${WEBHOOK_TOKEN}`) {
return res.status(401).json({ error: 'Unauthorized' });
}
next();
}
// Middleware: Validate payload
function validatePayload(req, res, next) {
const payload = req.body;
if (!payload._id || !payload._userId || !payload._ownerId) {
return res.status(400).json({ error: 'Invalid payload' });
}
next();
}
// Webhook handler
app.post(
'/webhooks/beedeez',
authenticateWebhook,
validatePayload,
async (req, res) => {
const certificate = req.body;
try {
// Determine event type
const now = new Date();
const expiryDate = certificate.expires
? new Date(certificate.expires)
: null;
const isExpired = expiryDate && expiryDate < now;
// Log receipt
console.log('Webhook received:', {
certificateId: certificate._id,
userId: certificate._userId,
eventType: isExpired ? 'expired' : 'completed',
});
// Respond immediately
res.status(200).json({
received: true,
certificateId: certificate._id,
});
// Process asynchronously
if (isExpired) {
await handleExpiredCertificate(certificate);
} else {
await handleCompletedCertificate(certificate);
}
} catch (error) {
console.error('Error processing webhook:', error);
// Still return 200 if we received it successfully
// Log error for investigation
}
},
);
async function handleCompletedCertificate(certificate) {
// Update HR system
await updateHRSystem(certificate);
// Send congratulations email
await sendCongratulationsEmail(certificate);
// Update analytics
await trackCertificateCompletion(certificate);
}
async function handleExpiredCertificate(certificate) {
// Mark as expired in compliance system
await markCertificateExpired(certificate);
// Trigger re-certification workflow
await triggerRecertification(certificate);
// Send renewal reminder
await sendRenewalReminder(certificate);
}
// Start server
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Webhook server listening on port ${PORT}`);
});
Next Steps
- Review Configuration Guide to set up your webhook
- Learn about Authentication to secure your endpoint
- Read Event Types to understand all available events
- Check Introduction for webhook concepts and best practices