Skip to main content

GitHub Webhooks

Receive real-time notifications when events happen in your GitHub repositories — issues created, PRs merged, workflows completed, and more. Webhook events are routed to Slack channels or DMs based on your subscription preferences.

Overview

The GitHub webhook system provides:

  • Organization-level webhook configuration with encrypted secrets
  • Per-user subscriptions with event and repository filtering
  • Delivery tracking with retry capability
  • Circuit breaker that auto-disables failing subscriptions
  • Secret rotation with 24-hour dual-acceptance window

Getting Started

Step 1: Create a Webhook Configuration (Admin)

Organization admins create a webhook config that generates a unique URL for GitHub:

  1. Navigate to Organization → Settings → Webhooks
  2. Click Create GitHub Webhook
  3. Configure:
    • Repositories to monitor (or all repos)
    • Events to receive (see Supported Events)
  4. Copy the generated Webhook URL and Secret
Save Your Secret

The webhook secret is shown only once at creation time. Store it securely — you'll need it when configuring the webhook in GitHub. If lost, you must rotate the secret.

Step 2: Configure in GitHub

  1. Go to your GitHub organization Settings → Webhooks → Add webhook
  2. Set:
    • Payload URL: The webhook URL from Step 1
    • Content type: application/json
    • Secret: The webhook secret from Step 1
  3. Select the events you want to receive
  4. Click Add webhook

Step 3: Subscribe to Events (Users)

Individual team members subscribe to receive specific events:

  1. Navigate to Organization → Settings → Webhooks → Subscriptions
  2. Click Add Subscription
  3. Choose:
    • Events you want to receive
    • Delivery target: Slack channel or DM
    • Filters: Specific repositories, branches, or authors
  4. Save your subscription

Webhook Configuration API

Organization admins manage webhook configs through these endpoints:

MethodEndpointDescription
POST/api/organizations/{id}/webhooks/githubCreate webhook config
GET/api/organizations/{id}/webhooks/githubGet config (secret masked)
PUT/api/organizations/{id}/webhooks/githubUpdate config
DELETE/api/organizations/{id}/webhooks/githubDelete config and all subscriptions
POST/api/organizations/{id}/webhooks/github/rotate-secretRotate webhook secret
POST/api/organizations/{id}/webhooks/github/testSend test webhook

Supported Events

EventDescription
pushCode pushed to a branch
pull_requestPR opened, closed, merged, or updated
pull_request_reviewPR review submitted
issuesIssue opened, closed, or updated
issue_commentComment on an issue or PR
createBranch or tag created
deleteBranch or tag deleted
workflow_runGitHub Actions workflow completed
releaseRelease published
starRepository starred

Subscription Management

Creating Subscriptions

Subscriptions define who receives which events and where:

FieldDescription
EventsWhich events to receive (e.g., pull_request, issues)
Target typechannel (Slack channel) or dm (direct message)
TargetSlack channel ID or user's linked Slack account
FiltersOptional repo, branch, or author filters

Subscription API

MethodEndpointDescription
GET/api/webhooks/github/subscriptionsList your subscriptions
POST/api/webhooks/github/subscriptionsCreate a subscription
PUT/api/webhooks/github/subscriptions/{id}Update a subscription
DELETE/api/webhooks/github/subscriptions/{id}Delete a subscription
Subscription Limits

Each organization can have up to 500 active subscriptions. If you're approaching this limit, consider consolidating subscriptions by using broader event filters.

Delivery Tracking

Every webhook delivery is recorded with status and metadata:

FieldDescription
StatusSuccess, Filtered, or Failed
Correlation IDUnique ID for tracing delivery across systems
Processing timeDuration from receipt to delivery
PayloadSanitized payload stored for failed deliveries

Delivery API

MethodEndpointDescription
GET/api/webhooks/deliveriesList recent deliveries
POST/api/webhooks/deliveries/{id}/retryRetry a failed delivery

Retrying Failed Deliveries

Failed deliveries can be retried manually:

  1. Navigate to Organization → Settings → Webhooks → Deliveries
  2. Find the failed delivery
  3. Click Retry

Or via API: POST /api/webhooks/deliveries/{id}/retry

Security

Signature Verification

Every incoming webhook is verified using HMAC-SHA256:

  1. GitHub signs each payload with your webhook secret
  2. The signature is sent in the X-Hub-Signature-256 header
  3. Bike4Mind recomputes the signature and compares using timing-safe comparison
  4. Invalid signatures are rejected with 401 Unauthorized
Timing-Safe Comparison

Signature verification uses constant-time comparison to prevent timing attacks. Never implement your own signature verification without this protection.

Secret Encryption

  • Webhook secrets are encrypted at rest using AES-256-GCM
  • Secrets are only decrypted in memory during signature verification
  • The SECRET_ENCRYPTION_KEY is stored as an environment variable, never in the database

Secret Rotation

To rotate a webhook secret without downtime:

  1. Call POST /api/organizations/{id}/webhooks/github/rotate-secret
  2. A new secret is generated and returned (one-time display)
  3. Both old and new secrets are accepted for 24 hours
  4. Update the secret in your GitHub webhook settings
  5. After 24 hours, only the new secret is accepted

Circuit Breaker

The circuit breaker protects against persistent delivery failures:

ThresholdBehavior
5 consecutive failuresSubscription is automatically disabled
Auto-disableNo further deliveries attempted until re-enabled
Re-enableUser manually re-enables in subscription settings
Monitoring Circuit Breaker

Check your subscription status regularly. If a subscription is auto-disabled, investigate the delivery failures before re-enabling. Common causes: Slack channel deleted, bot removed from channel, or Slack rate limiting.

Rate Limits

LimitValueScope
Incoming webhooksNo Bike4Mind-imposed limitPer webhook config
Outgoing Slack messagesSubject to Slack API rate limitsPer workspace
Delivery retries1 retry per deliveryPer delivery
GitHub's Webhook Limits

GitHub has its own limits on webhook deliveries. If GitHub can't reach your webhook URL, it will retry with exponential backoff for up to 3 days. See GitHub's webhook documentation.

Known Limitations

  • Repository-level webhooks are not supported — only organization-level
  • Webhook replays are limited to the last 30 days of deliveries
  • Payload size is capped at 1 MB — larger payloads are rejected with 413
  • Event filtering applies at the subscription level, not the webhook level — all events configured in GitHub are received, then filtered per subscription
  • Slack delivery only — webhook events can currently only be delivered to Slack channels or DMs (no email, no other services)

Troubleshooting

For common webhook issues, see the Troubleshooting Guide.

Quick fixes:

  • "Invalid signature" → Ensure the secret in GitHub matches the one shown in Bike4Mind
  • "Subscription auto-disabled" → Check that the Slack channel still exists and the bot is a member
  • "No deliveries received" → Verify the webhook URL is correct in GitHub settings and the webhook is active