Webhook Setup
Manually register webhooks for GitHub, GitLab, Bitbucket, Azure Repos, and Forgejo when automatic registration isn't possible.
Automatic webhook registration works for cloud providers when the integration has permission. Register manually for self-managed instances, restricted orgs, or when a webhook was deleted.
ScanDrix side
The webhook URL and rotating secret are shown under Settings → Integrations → <provider> → Webhooks:
URL: https://<your-host>/api/webhooks/<provider>
Secret: <shared secret> # rotate per integration
Provider recipes
GitHub
Settings → Webhooks → Add webhook
- Payload URL:
https://<your-host>/api/webhooks/github - Content type:
application/json - Secret: paste the ScanDrix secret
- Events: Let me select individual →
Pull requests,Pushes - Active: ✓
Verify with the redelivery button — ScanDrix answers ping events with 202.
GitLab
Settings → Webhooks
- URL:
https://<your-host>/api/webhooks/gitlab - Secret token: ScanDrix secret
- Triggers: ✓ Merge request events, ✓ Push events
- SSL verification: ✓
Bitbucket Cloud
Repository settings → Webhooks → Add webhook
- URL:
https://<your-host>/api/webhooks/bitbucket - Triggers: Pull request created, updated; Push
Bitbucket has no shared-secret header — bind the integration with your app password and rely on TLS; optionally allow-list ScanDrix egress IPs (shown in the dashboard).
Azure Repos
Project settings → Service hooks → New subscription → Webhooks
- Event: Pull request created (add a second for updated)
- URL:
https://<your-host>/api/webhooks/azure - Basic auth / secret: ScanDrix secret
Forgejo
Settings → Webhooks → Add
- Target URL:
https://<your-host>/api/webhooks/forgejo - Content type:
application/json - Secret: ScanDrix secret
- Events: push, pull_request
Signature validation
ScanDrix rejects unsigned or mismatched payloads:
| Provider | Header checked |
|---|---|
| GitHub | X-Hub-Signature-256 (HMAC-SHA256 of raw body) |
| GitLab | X-Gitlab-Token |
| Azure | basic-auth/secret header |
| Forgejo | X-Gitea-Signature |
The webhook secret is a credential. Never commit it, never log it, rotate it from the dashboard the moment it might be exposed — rotations take effect on the next delivery and the old secret is rejected immediately.
Verifying delivery
After saving, send a test event from the provider UI, then check Settings → Integrations → Last deliveries in ScanDrix — each shows status code, latency, and the last 1 KB of the response. Persistent 401 = secret mismatch; 404 = wrong path/provider segment; 400 = body stripped by a proxy (see Reverse Proxy & TLS).