Integration Guide

GitHub Webhook Integration Guide

Automate your CI/CD pipeline with GitHub webhooks. Learn how to trigger builds, deployments, and notifications when code is pushed, PRs are opened, or issues are created.

Why Use GitHub Webhooks?

GitHub webhooks enable real-time automation for your development workflow:

✓ Automated Deployments

Deploy to production when code is pushed to main branch

✓ CI/CD Pipelines

Trigger tests and builds on every pull request

✓ Team Notifications

Send Slack/Discord alerts for new issues or PRs

✓ Custom Automation

Build custom workflows for your team's needs

Step 1: Create Webhook Endpoint

Node.js / Express.js

const express = require('express');
const crypto = require('crypto');
const app = express();

app.post('/webhooks/github',
  express.json(),
  async (req, res) => {
    const signature = req.headers['x-hub-signature-256'];
    const event = req.headers['x-github-event'];
    const payload = req.body;
    
    // Verify signature (we'll add this next)
    if (!verifySignature(signature, JSON.stringify(payload))) {
      return res.sendStatus(401);
    }
    
    console.log(`Received ${event} event`);
    res.sendStatus(200);
  }
);

app.listen(3000);

Step 2: Configure Webhook in GitHub

  1. 1.Go to your repository → Settings → Webhooks → Add webhook
  2. 2.Enter Payload URL: https://yourapp.com/webhooks/github
  3. 3.Content type: application/json
  4. 4.Generate a secret (random string) and save it securely
  5. 5.Select events: "Just the push event" or "Let me select individual events"
  6. 6.Click "Add webhook"

Step 3: Verify Webhook Signatures

Signature Verification

const crypto = require('crypto');

function verifySignature(signature, payload) {
  const secret = process.env.GITHUB_WEBHOOK_SECRET;
  
  // Compute expected signature
  const hmac = crypto.createHmac('sha256', secret);
  const expectedSignature = 'sha256=' + hmac.update(payload).digest('hex');
  
  // Timing-safe comparison
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

app.post('/webhooks/github',
  express.json(),
  async (req, res) => {
    const signature = req.headers['x-hub-signature-256'];
    const payload = JSON.stringify(req.body);
    
    if (!verifySignature(signature, payload)) {
      console.error('Invalid signature');
      return res.sendStatus(401);
    }
    
    // Process webhook...
    res.sendStatus(200);
  }
);

Step 4: Handle Webhook Events

Event Handling Example

app.post('/webhooks/github',
  express.json(),
  async (req, res) => {
    const signature = req.headers['x-hub-signature-256'];
    const event = req.headers['x-github-event'];
    const payload = req.body;
    
    if (!verifySignature(signature, JSON.stringify(payload))) {
      return res.sendStatus(401);
    }
    
    switch (event) {
      case 'push':
        await handlePush(payload);
        break;
      
      case 'pull_request':
        await handlePullRequest(payload);
        break;
      
      case 'issues':
        await handleIssue(payload);
        break;
      
      case 'release':
        await handleRelease(payload);
        break;
      
      default:
        console.log(`Unhandled event: ${event}`);
    }
    
    res.sendStatus(200);
  }
);

async function handlePush(payload) {
  const branch = payload.ref.replace('refs/heads/', '');
  const commits = payload.commits;
  
  console.log(`Push to ${branch}: ${commits.length} commits`);
  
  // Trigger deployment for main branch
  if (branch === 'main') {
    await triggerDeployment({
      branch,
      commit: payload.after,
      pusher: payload.pusher.name
    });
  }
}

async function handlePullRequest(payload) {
  const action = payload.action; // opened, closed, synchronize
  const pr = payload.pull_request;
  
  if (action === 'opened') {
    console.log(`New PR #${pr.number}: ${pr.title}`);
    await runTests(pr.head.sha);
  }
}

Common GitHub Events

pushCode pushed to repository
pull_requestPR opened, closed, or updated
issuesIssue created or updated
releaseRelease published
workflow_runGitHub Actions workflow completed

Real-World Use Cases

Automated Deployments

Deploy to production when code is pushed to the main branch:

async function handlePush(payload) {
  const branch = payload.ref.replace('refs/heads/', '');
  
  if (branch === 'main') {
    await deployToProduction({
      commit: payload.after,
      author: payload.pusher.name
    });
  }
}

PR Notifications

Send Slack notifications when PRs are opened:

async function handlePullRequest(payload) {
  if (payload.action === 'opened') {
    await sendSlackMessage({
      text: `New PR: ${payload.pull_request.title}`,
      url: payload.pull_request.html_url,
      author: payload.pull_request.user.login
    });
  }
}

Best Practices

Always verify signatures

Prevent unauthorized webhook requests

Process asynchronously

Return 200 quickly, queue long-running tasks

Handle idempotency

GitHub may send duplicate webhooks

Simplify GitHub Webhook Management

hookVM provides a dashboard to inspect, replay, and debug GitHub webhooks. Perfect for CI/CD automation.