Skip to content

GitHub Integration

Receive and route GitHub webhooks for repositories, organizations, and GitHub Apps.

Setup

1. Create a Source in WebhookRelay

bash
curl -X POST https://api.webhookrelay.com/api/organizations/{orgId}/sources \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "GitHub Production",
    "slug": "github",
    "verificationConfig": {
      "type": "github",
      "secret": "your-webhook-secret"
    }
  }'

Save your webhook URL:

https://api.webhookrelay.com/ingest/{orgSlug}/github

2. Configure GitHub Webhook

Repository Webhook

  1. Go to your repository on GitHub
  2. Navigate to SettingsWebhooks
  3. Click Add webhook
  4. Enter your WebhookRelay URL as the Payload URL
  5. Set Content type to application/json
  6. Enter your Secret (same as configured in the source)
  7. Select events or choose Send me everything
  8. Click Add webhook

Organization Webhook

  1. Go to your organization on GitHub
  2. Navigate to SettingsWebhooks
  3. Follow the same steps as repository webhook

GitHub App Webhook

  1. Go to your GitHub App settings
  2. Set the Webhook URL to your WebhookRelay URL
  3. Enter the Webhook secret
  4. Enable desired events

3. Create Destinations and Routes

bash
# Create a destination
curl -X POST https://api.webhookrelay.com/api/organizations/{orgId}/destinations \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"name": "My App", "url": "https://myapp.com/webhooks/github"}'

# Create a route
curl -X POST https://api.webhookrelay.com/api/organizations/{orgId}/routes \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"name": "GitHub to My App", "sourceId": "src_...", "destinationIds": ["dst_..."]}'

Signature Verification

GitHub signs webhooks with HMAC-SHA256. The signature is sent in the X-Hub-Signature-256 header:

X-Hub-Signature-256: sha256=abc123...

WebhookRelay automatically verifies this signature when you configure:

json
{
  "verificationConfig": {
    "type": "github",
    "secret": "your-webhook-secret"
  }
}

Common Events

Push Events

Triggered when code is pushed to a branch.

json
{
  "ref": "refs/heads/main",
  "before": "abc123",
  "after": "def456",
  "repository": {
    "id": 123456,
    "full_name": "owner/repo",
    "private": false
  },
  "pusher": {
    "name": "username",
    "email": "user@example.com"
  },
  "commits": [
    {
      "id": "def456",
      "message": "Update README",
      "author": {
        "name": "User",
        "email": "user@example.com"
      }
    }
  ]
}

Pull Request Events

Triggered for PR actions (opened, closed, merged, etc.).

json
{
  "action": "opened",
  "number": 42,
  "pull_request": {
    "id": 789,
    "title": "Add new feature",
    "state": "open",
    "head": {
      "ref": "feature-branch",
      "sha": "abc123"
    },
    "base": {
      "ref": "main",
      "sha": "def456"
    },
    "user": {
      "login": "username"
    }
  },
  "repository": {
    "full_name": "owner/repo"
  }
}

Issue Events

Triggered for issue actions.

json
{
  "action": "opened",
  "issue": {
    "id": 456,
    "number": 10,
    "title": "Bug report",
    "state": "open",
    "user": {
      "login": "reporter"
    },
    "labels": [
      {"name": "bug"}
    ]
  },
  "repository": {
    "full_name": "owner/repo"
  }
}

Transform Examples

Slack Notification for Push

javascript
function transform(payload) {
  const commits = payload.commits || [];
  const commitList = commits
    .slice(0, 5)
    .map(c => `• ${c.message.split('\n')[0]}`)
    .join('\n');

  return {
    blocks: [
      {
        type: "header",
        text: {
          type: "plain_text",
          text: `Push to ${payload.repository.full_name}`
        }
      },
      {
        type: "section",
        fields: [
          {
            type: "mrkdwn",
            text: `*Branch:*\n${payload.ref.replace('refs/heads/', '')}`
          },
          {
            type: "mrkdwn",
            text: `*Pusher:*\n${payload.pusher.name}`
          }
        ]
      },
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text: `*Commits (${commits.length}):*\n${commitList}`
        }
      }
    ]
  };
}

Discord Notification for PR

javascript
function transform(payload) {
  const pr = payload.pull_request;
  const action = payload.action;

  const colors = {
    opened: 0x28a745,
    closed: 0xd73a49,
    merged: 0x6f42c1
  };

  return {
    embeds: [{
      title: `PR #${pr.number}: ${pr.title}`,
      url: pr.html_url,
      color: colors[action] || 0x586069,
      fields: [
        { name: "Action", value: action, inline: true },
        { name: "Author", value: pr.user.login, inline: true },
        { name: "Branch", value: `${pr.head.ref} → ${pr.base.ref}`, inline: true }
      ],
      timestamp: new Date().toISOString()
    }]
  };
}

Filter Examples

Only Push to Main

json
{
  "name": "Main Branch Pushes",
  "logic": "and",
  "conditions": [
    {
      "field": "ref",
      "operator": "equals",
      "value": "refs/heads/main"
    }
  ]
}

PR Opened or Merged

json
{
  "name": "PR Opened or Merged",
  "logic": "or",
  "conditions": [
    {
      "field": "action",
      "operator": "equals",
      "value": "opened"
    },
    {
      "field": "pull_request.merged",
      "operator": "equals",
      "value": "true"
    }
  ]
}

Exclude Bot Users

json
{
  "name": "Non-Bot Events",
  "logic": "and",
  "conditions": [
    {
      "field": "sender.type",
      "operator": "not_equals",
      "value": "Bot"
    }
  ]
}

Headers

GitHub sends these headers with webhooks:

HeaderDescription
X-GitHub-EventEvent type (push, pull_request, etc.)
X-GitHub-DeliveryUnique delivery ID
X-Hub-Signature-256HMAC-SHA256 signature
X-GitHub-Hook-IDWebhook configuration ID
X-GitHub-Hook-Installation-Target-IDInstallation target
X-GitHub-Hook-Installation-Target-TypeTarget type (repository, organization)

Troubleshooting

Webhook Not Triggering

  1. Check GitHub's webhook delivery logs in repository settings
  2. Verify the payload URL is correct
  3. Ensure the webhook is active (not disabled)

Signature Verification Failed

  1. Verify the secret matches exactly (no extra spaces)
  2. Check if you're using the correct secret for the environment
  3. Ensure the payload isn't being modified by proxies

Missing Events

  1. Check which events are selected in GitHub webhook settings
  2. Verify filters aren't blocking expected events
  3. Check if the repository/org has required permissions

Best Practices

  1. Use secrets: Always configure a webhook secret for security

  2. Select specific events: Only subscribe to events you need

  3. Use filters: Filter events to reduce unnecessary processing

  4. Monitor deliveries: Check GitHub's webhook logs for failures

  5. Separate by environment: Use different sources for prod/staging/dev

Released under the MIT License.