Skip to main content

Packages And Container Registry Webhooks

Webhook Configuration

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 TypeDescriptionTrigger Conditions
artifact:createdEvent broadcast when an artifact has been createdNew artifact created
artifact:deletedEvent broadcast when an artifact is deletedExisting artifact gets deleted

Webhook Security

All webhooks from Unizo include security headers to verify authenticity:

Headers

HeaderDescription
x-unizo-event-typeThe type of event that triggered the webhook
x-unizo-signatureHMAC SHA-256 signature for request validation
x-unizo-timestampUnix timestamp when the event was sent
x-unizo-delivery-idUnique 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

Triggered when a new artifact, package, or container image is uploaded to your package registry.
POSThttps://api.yourapp.com/webhooks/unizo/scm
Best Practice: Use a dedicated webhook endpoint that can handle multiple event types. You have two architectural options:
• 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 architecture
Headers
NameTypeRequiredDescription
x-unizo-event-typestringYesThe type of event that was triggered
x-unizo-signaturestringYesHMAC SHA-256 signature
Request Body Schema
PropertyTypeRequiredDescription
typestringYesEvent type identifier
versionstringYesWebhook payload version
contentTypestringYesBranch name/identifier
artifactstringYesArtifact Name
artifact.idstringYesArtifact ID
artifact.keystringYesArtifact Key
artifact.namestringYesArtifact Name
artifact.pathstringYesArtifact Path
integration.typestringYesIntegration type
integration.idstringYesIntegration ID
integration.namestringYesIntegration 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 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Artifact Deleted

artifact:deleted

Triggered when an artifact is removed from the package registry.
POSThttps://api.yourapp.com/webhooks/unizo/scm
Best Practice: Use a dedicated webhook endpoint that can handle multiple event types. You have two architectural options:
• 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 architecture
Headers
NameTypeRequiredDescription
x-unizo-event-typestringYesThe type of event that was triggered
x-unizo-signaturestringYesHMAC SHA-256 signature
Request Body Schema
PropertyTypeRequiredDescription
typestringYesEvent type identifier
versionstringYesWebhook payload version
contentTypestringYesBranch name/identifier
artifactstringYesArtifact Name
artifact.idstringYesArtifact ID
artifact.keystringYesArtifact Key
artifact.pathstringYesArtifact Path
artifact.namestringYesArtifact Name
integration.typestringYesIntegration type
integration.idstringYesIntegration ID
integration.namestringYesIntegration 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 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid 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: