Packages And Container Registry Webhooks
To set up webhooks for your integration, visit the Unizo Console Webhooks section for step-by-step configuration guide.
Overview
Unizo's Package Registry API provides webhooks to notify your application when important events occur in your package registries and artifact repositories. These real-time notifications enable you to build automated CI/CD workflows, maintain artifact synchronization, track package usage, and ensure security compliance.
Our platform normalizes webhook events from various package registry providers (JFrog Artifactory, Nexus Repository, Docker Registry, GitHub Packages, etc.) into a consistent format, making it easy to handle artifact events across different registry platforms.
Supported Event Types
Event Type | Description | Trigger Conditions |
---|---|---|
artifact:created | Event broadcast when an artifact has been created | New artifact created |
artifact:deleted | Event broadcast when an artifact is deleted | Existing artifact gets deleted |
Webhook Security
All webhooks from Unizo include security headers to verify authenticity:
Headers
Header | Description |
---|---|
x-unizo-event-type | The type of event that triggered the webhook |
x-unizo-signature | HMAC SHA-256 signature for request validation |
x-unizo-timestamp | Unix timestamp when the event was sent |
x-unizo-delivery-id | Unique identifier for this webhook delivery |
Signature Verification
Verify the authenticity of incoming webhooks using HMAC SHA-256:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature, 'hex'),
Buffer.from(expectedSignature, 'hex')
);
}
Artifact Events
Artifact Created
artifact:created
• Single endpoint:
https://api.yourapp.com/webhooks/unizo
- Route all events to one handler• Category-based endpoints:
https://api.yourapp.com/webhooks/unizo/scm
- Route by category (scm, ticketing, etc.) for microservices architectureHeaders
Name | Type | Required | Description |
---|---|---|---|
x-unizo-event-type | string | Yes | The type of event that was triggered |
x-unizo-signature | string | Yes | HMAC SHA-256 signature |
Request Body Schema
Property | Type | Required | Description |
---|---|---|---|
type | string | Yes | Event type identifier |
version | string | Yes | Webhook payload version |
contentType | string | Yes | Branch name/identifier |
artifact | string | Yes | Artifact Name |
artifact.id | string | Yes | Artifact ID |
artifact.key | string | Yes | Artifact Key |
artifact.name | string | Yes | Artifact Name |
artifact.path | string | Yes | Artifact Path |
integration.type | string | Yes | Integration type |
integration.id | string | Yes | Integration ID |
integration.name | string | Yes | Integration display name |
Example Payload
{"type": "artifact:created","version": "1.0.0","contentType": "application/json","artifact": {"id": "testing","key": "testing-webhook","name": "manifest.json","path": "unizoinc/otg-event-catcher/v1.0.0/manifest.json"},"integration": {"type": "PCR","id": "864e88c4-69ce-4df7-a2a1-ab3c4e439fac","name": "JF_Secu_1734358143372"}}
Response
200 OK | Webhook processed successfully |
400 Bad Request | Invalid webhook payload |
401 Unauthorized | Invalid or missing signature |
Artifact Deleted
artifact:deleted
• Single endpoint:
https://api.yourapp.com/webhooks/unizo
- Route all events to one handler• Category-based endpoints:
https://api.yourapp.com/webhooks/unizo/scm
- Route by category (scm, ticketing, etc.) for microservices architectureHeaders
Name | Type | Required | Description |
---|---|---|---|
x-unizo-event-type | string | Yes | The type of event that was triggered |
x-unizo-signature | string | Yes | HMAC SHA-256 signature |
Request Body Schema
Property | Type | Required | Description |
---|---|---|---|
type | string | Yes | Event type identifier |
version | string | Yes | Webhook payload version |
contentType | string | Yes | Branch name/identifier |
artifact | string | Yes | Artifact Name |
artifact.id | string | Yes | Artifact ID |
artifact.key | string | Yes | Artifact Key |
artifact.path | string | Yes | Artifact Path |
artifact.name | string | Yes | Artifact Name |
integration.type | string | Yes | Integration type |
integration.id | string | Yes | Integration ID |
integration.name | string | Yes | Integration display name |
Example Payload
{"type": "artifact:deleted","version": "1.0.0","contentType": "application/json","artifact": {"id": "docker-trial","key": "docker-trial-webhook","path": "exposures/latest/manifest.json","name": "manifest.json"},"integration": {"type": "PCR","id": "be03cab2-e9d2-4d95-ad45-c5411b2be10a","name": "JF_Secu_1734088106577"}}
Response
200 OK | Webhook processed successfully |
400 Bad Request | Invalid webhook payload |
401 Unauthorized | Invalid or missing signature |
Webhook Delivery & Retries
Unizo implements a robust delivery system with automatic retries to ensure your webhooks are delivered reliably:
- Timeout: 30 seconds per delivery attempt
- Retry Schedule: 5 attempts with exponential backoff
- Attempt 1: Immediate
- Attempt 2: 1 minute delay
- Attempt 3: 5 minutes delay
- Attempt 4: 30 minutes delay
- Attempt 5: 2 hours delay
- Success Criteria: HTTP status codes 200-299
- Failure Handling: After 5 failed attempts, the webhook is marked as failed
Best Practices
1. Idempotency
Always implement idempotent webhook handlers using the x-unizo-delivery-id
header:
Idempotent Webhook Handler
// Example: Handling webhooks idempotently
app.post('/webhooks/pcr', async (req, res) => {
const deliveryId = req.headers['x-unizo-delivery-id'];
// Check if we've already processed this delivery
const existingDelivery = await db.webhookDeliveries.findOne({
deliveryId
});
if (existingDelivery) {
console.log(`Duplicate delivery detected: ${deliveryId}`);
return res.status(200).json({
status: 'already_processed'
});
}
// Process the webhook
try {
await processArtifactEvent(req.body);
// Record the delivery
await db.webhookDeliveries.create({
deliveryId,
processedAt: new Date()
});
res.status(200).json({ status: 'success' });
} catch (error) {
console.error('Webhook processing failed:', error);
res.status(500).json({ status: 'error' });
}
});
2. CI/CD Integration
Integrate package events into your CI/CD pipeline:
CI/CD Pipeline Integration
// Example: Trigger deployments on new releases
app.post('/webhooks/pcr', async (req, res) => {
const { type, data } = req.body;
// Acknowledge receipt
res.status(200).json({ status: 'received' });
switch (type) {
case 'version:released':
// Trigger deployment pipeline
if (data.release.version.match(/^d+.d+.0$/)) {
// Major or minor release - deploy to staging
await cicdApi.triggerPipeline({
pipeline: 'deploy-staging',
parameters: {
package: data.package.name,
version: data.release.version,
artifacts: data.release.artifacts
}
});
// Notify team
await slackApi.postMessage({
channel: '#releases',
text: `🚀 New release: ${data.package.name} v${data.release.version}`,
attachments: [{
title: 'Release Notes',
text: data.release.release_notes
}]
});
}
break;
case 'scan:completed':
// Check security policy
if (data.policy_status === 'fail') {
// Block deployment
await cicdApi.failPipeline({
buildId: data.artifact.id,
reason: 'Security scan failed',
details: `Found ${data.vulnerabilities.critical} critical vulnerabilities`
});
// Create security ticket
await jiraApi.createIssue({
type: 'Security',
priority: 'Critical',
summary: `Security vulnerabilities in ${data.artifact.name}:${data.artifact.version}`,
description: formatVulnerabilities(data.vulnerabilities)
});
}
break;
}
});
3. Artifact Tracking and Compliance
Maintain artifact inventory and compliance records:
Artifact Compliance Tracking
// Example: Track artifacts for compliance
app.post('/webhooks/pcr', async (req, res) => {
const { type, data, integration } = req.body;
// Create audit record
const auditEntry = {
timestamp: new Date(),
eventType: type,
integration: integration.name,
artifact: {
id: data.artifact?.id,
name: data.artifact?.name,
version: data.artifact?.version,
type: data.artifact?.type
}
};
switch (type) {
case 'artifact:created':
// Register in artifact inventory
await inventoryDb.artifacts.create({
...data.artifact,
status: 'active',
compliance: {
scanned: false,
approved: false,
licenses: []
}
});
// Trigger compliance checks
await complianceApi.scanArtifact({
artifactId: data.artifact.id,
checks: ['license', 'security', 'quality']
});
break;
case 'vulnerability:detected':
// Update compliance status
await inventoryDb.artifacts.update(data.artifact.id, {
compliance: {
scanned: true,
securityStatus: data.policy_status,
vulnerabilities: {
critical: data.vulnerabilities.critical,
high: data.vulnerabilities.high,
lastScan: data.scan.completed_at
}
}
});
// Generate compliance report
if (data.vulnerabilities.critical > 0) {
await reportingApi.generateSecurityReport({
artifact: data.artifact,
vulnerabilities: data.vulnerabilities,
recipients: ['security-team@company.com']
});
}
break;
}
// Store audit trail
await auditDb.packageEvents.create(auditEntry);
res.status(200).json({ status: 'tracked' });
});
Need Help?
For webhook-related support:
- Contact support at support@unizo.ai