GitHub
Configure the webhook in GitHub
GitHub webhooks can be set at the repository, organization, or GitHub App level.
Repository webhook
- Repository → Settings → Webhooks → Add webhook.
- Payload URL:
https://splithook.com/e/{slug}. - Content type:
application/json. - Secret: generate a random string (e.g.
openssl rand -hex 32) and paste it here. - Select events (or "Send me everything").
- 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
- Settings → Signing secrets → New.
- Provider: GitHub.
- Paste the same random string you configured in GitHub.
- 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'