GitHub

Updated May 02, 2026

Configure the webhook in GitHub

GitHub webhooks can be set at the repository, organization, or GitHub App level.

Repository webhook

  1. Repository → Settings → Webhooks → Add webhook.
  2. Payload URL: https://splithook.com/e/{slug}.
  3. Content type: application/json.
  4. Secret: generate a random string (e.g. openssl rand -hex 32) and paste it here.
  5. Select events (or "Send me everything").
  6. Add webhook.

Organization webhook

Organization → Settings → Webhooks — same steps.

GitHub App

In your App settings → Webhook URL: https://splithook.com/e/{slug}. Set a Webhook secret.

Add the signing secret to Splithook

  1. Settings → Signing secrets → New.
  2. Provider: GitHub.
  3. Paste the same random string you configured in GitHub.
  4. In your destination, set Signing mode to Re-sign, select this secret.

Verify signatures in your handler

// Node.js — using @octokit/webhooks
import { Webhooks } from '@octokit/webhooks';
const webhooks = new Webhooks({ secret: process.env.GITHUB_WEBHOOK_SECRET });

app.post('/webhooks/github', async (req, res) => {
  const signature = req.headers['x-hub-signature-256'] as string;
  const body = await getRawBody(req);
  if (!await webhooks.verify(body, signature)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(body);
  // handle event...
  res.sendStatus(200);
});
# Python
import hmac, hashlib
def verify_signature(payload_body, secret_token, signature_header):
    expected = 'sha256=' + hmac.new(
        secret_token.encode(), payload_body, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)

How Splithook re-signs GitHub events

GitHub's signature format:

x-hub-signature-256: sha256=abc123...

The signed string is the raw request body — no timestamp. On replay, Splithook recomputes:

x-hub-signature-256: sha256=HMAC-SHA256(secret, body)

Because there is no timestamp in GitHub's scheme, replays work identically to live events. There is no 5-minute window to worry about.

Filtering by event type

GitHub sends the event type in the X-GitHub-Event header, which Splithook copies to event_type:

event_type == 'push'
event_type == 'pull_request'
event_type == 'issues'
event_type in ['push', 'pull_request']

Filter by branch for push events:

event_type == 'push' and body.ref == 'refs/heads/main'

Filter by action for pull requests:

event_type == 'pull_request' and body.action == 'opened'