Skip to main content

SCM Webhooks

Webhooks enable your applications to receive real-time notifications when events occur in your source code repositories. This eliminates the need for polling and ensures your systems stay synchronized with code changes across all integrated platforms.

Unizo normalizes webhook events from GitHub, GitLab, Bitbucket, Azure DevOps, and other SCM providers into a consistent format. This means you write your webhook handler once and it works with all supported platforms.

Webhook Configuration

To set up webhooks for your integration, visit the Unizo Console Webhooks section for step-by-step configuration guide.

Supported Event Types

These are the event types currently supported by Unizo's SCM webhooks. The list keeps growing as we add support for more events across different platforms.

Event TypeDescriptionTrigger Conditions
organization:renamedEvent broadcast when the organization's name was changedOrganization Renamed
organization:deletedEvent broadcast when an organization is disconnectedOrganization Deleted
repository:createdEvent broadcast when a new repository is createdRepository Created
repository:renamedEvent broadcast when a repository is renamedRepository Renamed
repository:deletedEvent broadcast when a repository is deletedRepository Deleted
branch:createdA new branch has been createdBranch creation from UI, API, or push
branch:deletedA branch has been deletedBranch deletion from UI, API, or after merge
commit:createdEvent broadcast when a new commit is pushed to a branchCommit Created
commit:updatedEvent broadcast when a commit is updatedCommit Updated

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')
  );
}

Organization Events

Organization Renamed

organization:renamed

Event broadcast when the organization's name was changed
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
organizationstringYesOrganization name
organization.idstringYesOrganization ID
organization.keystringYesOrganization key
organization.urlstringYes Organization URL
organization.fromstringYesSource repository
organization.tostringYesTarget repository
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration ID
integration.namestringYesIntegration display name
Example Payload
{
"type": "organization:renamed",
"version": "1.0.0",
"contentType": "application/json",
"organization": {
"id": "167400081",
"key": "Bts-1tegrate-Org-update",
"url": "https://api.github.com/orgs/Bts-1tegrate-Org-update",
"from": "Bts-1tegrate-Org",
"to": "Bts-1tegrate-Org-update"
},
"integration": {
"type": "SCM",
"id": "f8f0cc49-a656-4668-9d64-43cb2c8e5f90",
"name": "Gi_Secu_1746454494408"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Organization Deleted

organization:deleted

Event broadcast when an organization is disconnected
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
organizationstringYesOrganization name
organization.idstringYesOrganization ID
organization.keystringYesOrganization key
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration ID
integration.namestringYesIntegration display name
Example Payload
{
"type": "organization:deleted",
"version": "1.0.0",
"contentType": "application/json",
"organization": {
"id": "210385971",
"key": "webhookorgtest"
},
"integration": {
"type": "SCM",
"id": "c1686c58-90d0-4c00-b07b-92476beb9137",
"name": "Gi_Secu_1746454781501"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Repository Events

Repository Created

repository:created

Event broadcast when a new repository is created
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
repositorystringYesRepository name
repository.idstringYesRepository ID
repository.keystringYesRepository key
repository.statestringYesRepository state
repository.createdDateTimestringYesRepository createdDateTime
repository.urlstringYesRepository url
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration ID
integration.namestringYesIntegration display name
Example Payload
{
"type": "repository:created",
"version": "1.0.0",
"contentType": "application/json",
"repository": {
"id": "repo-enterprise-sec-9971",
"key": "cloud-compliance-engine",
"state": "active",
"summary": "Infrastructure-as-Code (IaC) policies and scanning tools for cloud compliance",
"createdDateTime": "2025-05-05T18:20:45Z",
"url": "https://git.unizo.io/enterprise/cloud-compliance-engine"
},
"integration": {
"type": "SCM",
"id": "0c92e542-fb3e-4027-98c4-7235a691b997",
"name": "Bitbucket-SecOps"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Repository Renamed

repository:renamed

Event broadcast when a new repository is renamed
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
repositorystringYesRepository name
repository.idstringYesRepository ID
repository.keystringYesRepository key
repository.createdDateTimestringYesRepository createdDateTime
repository.fromstringYesSource Repository Name
repository.tostringYes Target Repository Name
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration ID
integration.namestringYesIntegration display name
Example Payload
{
"type": "repository:renamed",
"version": "1.0.0",
"contentType": "application/json",
"repository": {
"id": "978118703",
"key": "Demo-testing",
"createdDateTime": "2025-05-05T13:59:18Z",
"from": "Demo-testing1",
"to": "Demo-testing"
},
"integration": {
"type": "SCM",
"id": "14616a42-2a4a-42b2-b167-030908d6fc17",
"name": "Gi_Secu_1746452195518"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Repository Deleted

repository:deleted

Event broadcast when a new repository is renamed
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
repositorystringYesRepository name
repository.idstringYesRepository ID
repository.keystringYesRepository key
repository.createdDateTimestringYesRepository createdDateTime
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration ID
integration.namestringYesIntegration display name
Example Payload
{
"type": "repository:deleted",
"version": "1.0.0",
"contentType": "application/json",
"repository": {
"id": "978118703",
"key": "Demo-testing",
"createdDateTime": "2025-05-05T14:00:17Z"
},
"integration": {
"type": "SCM",
"id": "14616a42-2a4a-42b2-b167-030908d6fc17",
"name": "Gi_Secu_1746452195518"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Branch Events

Branch Created

branch:created

Triggered when a new branch is created in a repository
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
branchstringYesBranch name/identifier
branch.idstringYesBranch Id
branch.keystringYesBranch Key
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration id
integration.namestringYesIntegration display name
Example Payload
{
"type": "branch:created",
"version": "1.0.0",
"contentType": "application/json",
"branch": {
"id": "Shruthi089-patch-1",
"key": "Shruthi089-patch-1"
},
"integration": {
"type": "SCM",
"id": "14616a42-2a4a-42b2-b167-030908d6fc17",
"name": "Gi_Secu_1746452195518"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Branch Deleted

branch:deleted

Triggered when a branch is deleted from a repository
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
branchstringYesBranch name/identifier
branch.idstringYesBranch Id
branch.keystringYesBranch Key
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration id
integration.namestringYesIntegration display name
Example Payload
{
"type": "branch:deleted",
"version": "1.0.0",
"contentType": "application/json",
"branch": {
"id": "Testingdelete",
"key": "Testingdelete"
},
"integration": {
"type": "SCM",
"id": "14616a42-2a4a-42b2-b167-030908d6fc17",
"name": "Gi_Secu_1746452195518"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Commit Events

Commit Created

commit:created

Event broadcast when a new commit is pushed to a branch
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
commitstringYesArray of commit objects
commit.idstringYesCommit Id
commit.messagestringYesCommit message
commit.authorstringYesCommit author details
commit.author.namestringYesAuthor name
commit.author.emailstringYesAuthor email
committerstringYesCommitter
committer.namestringYesCommitter name
committer.emailstringYesCommitter email
createdDateTimestringYesCommitter created Timestamp
urlstringYesURL
repositorystringYesRepository name
repository.idstringYesRepository ID
repository.keystringYesRepository key
repository.urlstringYesRepository url
branchstringYesBranch name/identifier
branch.idstringYesBranch Id
branch.keystringYesBranch Key
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration id
integration.namestringYesIntegration display name
Example Payload
{
"type": "commit:created",
"version": "1.0.0",
"contentType": "application/json",
"commit": {
"id": "a1b2c3d4e5f6g7h8i9j0k1!@#",
"message": "Add new feature: User authentication",
"author": {
"name": "John Doe",
"email": "john.doe@example.com"
},
"committer": {
"name": "Jane Smith",
"email": "jane.smith@example.com"
},
"createdDateTime": "2025-05-05T15:30:00Z",
"url": "https://git.unizo.io/enterprise/cloud-compliance-engine/commit/a1b2c3d4e5f6g7h8i9j0k1!@#"
},
"repository": {
"id": "repo-enterprise-sec-9971",
"key": "cloud-compliance-engine",
"url": "https://git.unizo.io/enterprise/cloud-compliance-engine"
},
"branch": {
"id": "main",
"key": "main"
},
"integration": {
"type": "SCM",
"id": "0c92e542-fb3e-4027-98c4-7235a691b997",
"name": "Bitbucket-SecOps"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Commit Updated

commit:updated

Event broadcast when a commit is updated
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
commitstringYesArray of commit objects
commit.idstringYesCommit Id
commit.messagestringYesCommit message
commit.authorstringYesCommit author details
commit.author.namestringYesAuthor name
commit.author.emailstringYesAuthor email
committerstringYesCommitter
committer.namestringYesCommitter name
committer.emailstringYesCommitter email
createdDateTimestringYesCommitter created Timestamp
urlstringYesURL
repositorystringYesRepository name
repository.idstringYesRepository ID
repository.keystringYesRepository key
repository.urlstringYesRepository url
branchstringYesBranch name/identifier
branch.idstringYesBranch Id
branch.keystringYesBranch Key
integrationstringYesIntegration name
integration.typestringYesIntegration type
integration.idstringYesIntegration id
integration.namestringYesIntegration display name
Example Payload
{
"type": "commit:updated",
"version": "1.0.0",
"contentType": "application/json",
"commit": {
"id": "a1b2c3d4e5f6g7h8i9j0k1!@#",
"message": "Update: Add more tests for user authentication",
"author": {
"name": "John Doe",
"email": "john.doe@example.com"
},
"committer": {
"name": "Jane Smith",
"email": "jane.smith@example.com"
},
"createdDateTime": "2025-05-05T16:45:00Z",
"url": "https://git.unizo.io/enterprise/cloud-compliance-engine/commit/a1b2c3d4e5f6g7h8i9j0k1!@#"
},
"repository": {
"id": "repo-enterprise-sec-9971",
"key": "cloud-compliance-engine",
"url": "https://git.unizo.io/enterprise/cloud-compliance-engine"
},
"branch": {
"id": "main",
"key": "main"
},
"integration": {
"type": "SCM",
"id": "0c92e542-fb3e-4027-98c4-7235a691b997",
"name": "Bitbucket-SecOps"
}
}
Response
200 OKWebhook processed successfully
400 Bad RequestInvalid webhook payload
401 UnauthorizedInvalid or missing signature

Webhook Delivery & Retries

Unizo implements automatic retry logic for failed webhook deliveries:

  1. Initial Delivery: Immediate
  2. First Retry: After 1 minute
  3. Second Retry: After 5 minutes
  4. Third Retry: After 15 minutes
  5. Final Retry: After 1 hour

Webhooks are considered failed if:

  • Your endpoint returns a non-2xx status code
  • Connection timeout (30 seconds)
  • SSL/TLS errors

Best Practices

1. Idempotency

Idempotent Webhook Handler

async function handleWebhook(request) {
const deliveryId = request.headers['x-unizo-delivery-id'];

// Check if already processed
if (await isProcessed(deliveryId)) {
  return { status: 200, message: 'Already processed' };
}

// Process webhook
await processWebhook(request.body);

// Mark as processed
await markProcessed(deliveryId);

return { status: 200 };
}

2. Async Processing

Asynchronous Processing

app.post('/webhooks/scm', (req, res) => {
// Validate signature
if (!verifySignature(req)) {
  return res.status(401).send('Invalid signature');
}

// Queue for processing
webhookQueue.add(req.body);

// Return immediately
res.status(200).send('OK');
});

3. Error Handling

Comprehensive Error Handling

async function processWebhook(payload) {
try {
  switch (payload.type) {
    case 'branch:created':
      await handleBranchCreated(payload);
      break;
    case 'pull_request:merged':
      await handlePullRequestMerged(payload);
      break;
    default:
      logger.warn(`Unknown webhook type: ${payload.type}`);
  }
} catch (error) {
  logger.error('Webhook processing failed', {
    error: error.message,
    payload,
    stack: error.stack
  });
  throw error;
}
}

Need Help?

For webhook-related support: