Webhooks
Webhooks notify external services when events occur in your repositories. Use them to trigger CI/CD pipelines, update issue trackers, or integrate with other tools.
Creating a Webhook
Navigate to Settings
Go to Repository Settings → Webhooks or Organization Settings → Webhooks
Add Webhook
Click Add Webhook and configure:
- Payload URL: The endpoint to receive events
- Secret: Optional shared secret for signature verification
- Events: Which events trigger the webhook
Test Webhook
Click Test to send a ping event and verify your endpoint.
Webhook Configuration
| Setting | Description | Default |
|---|---|---|
url | HTTPS endpoint to receive payloads | Required |
secret | Secret for HMAC signature | Optional |
contentType | Payload format | application/json |
events | Array of event types | Required |
isActive | Enable/disable webhook | true |
maxRetries | Retry count on failure | 3 |
retryIntervalSeconds | Seconds between retries | 60 |
Event Types
Repository Events
| Event | Description |
|---|---|
push | Commits pushed to any branch |
create | Branch or tag created |
delete | Branch or tag deleted |
release | Release created or updated |
Pull Request Events
| Event | Description |
|---|---|
pull_request.opened | New PR created |
pull_request.closed | PR closed (merged or not) |
pull_request.merged | PR merged |
pull_request.updated | PR updated (new commits, title change) |
pull_request.review_requested | Review requested |
pull_request.review_submitted | Review submitted |
Issue Events
| Event | Description |
|---|---|
issue.opened | New issue created |
issue.closed | Issue closed |
issue.updated | Issue updated |
issue.commented | New comment on issue |
CI Events
| Event | Description |
|---|---|
ci.run_started | CI run started |
ci.run_completed | CI run completed |
ci.job_completed | Individual job completed |
AI Review Events
| Event | Description |
|---|---|
ai_review.started | AI review started |
ai_review.completed | AI review completed |
ai_review.suggestion_applied | AI suggestion was applied |
Payload Format
All webhooks include standard headers:
POST /your-webhook-endpoint HTTP/1.1
Content-Type: application/json
X-Statly-Event: push
X-Statly-Delivery: delivery_xxx
X-Statly-Signature: sha256=abc123...Example: Push Event
{
"event": "push",
"repository": {
"id": "repo_xxx",
"name": "my-app",
"fullName": "my-org/my-app"
},
"sender": {
"id": "user_xxx",
"name": "John Doe",
"email": "[email protected]"
},
"ref": "refs/heads/main",
"before": "abc123",
"after": "def456",
"commits": [
{
"sha": "def456",
"message": "Add new feature",
"author": {
"name": "John Doe",
"email": "[email protected]"
},
"timestamp": "2024-01-01T00:00:00Z"
}
],
"timestamp": "2024-01-01T00:00:00Z"
}Example: Pull Request Event
{
"event": "pull_request.opened",
"action": "opened",
"repository": {
"id": "repo_xxx",
"name": "my-app",
"fullName": "my-org/my-app"
},
"pullRequest": {
"id": "pr_xxx",
"number": 42,
"title": "Add new feature",
"body": "This PR adds...",
"state": "open",
"sourceBranch": "feature/new-feature",
"targetBranch": "main",
"headSha": "abc123",
"author": {
"id": "user_xxx",
"name": "John Doe"
}
},
"sender": {
"id": "user_xxx",
"name": "John Doe"
},
"timestamp": "2024-01-01T00:00:00Z"
}Signature Verification
When a secret is configured, verify the signature:
const crypto = require('crypto');
function verifySignature(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your handler
app.post('/webhook', (req, res) => {
const signature = req.headers['x-statly-signature'];
const isValid = verifySignature(
JSON.stringify(req.body),
signature,
process.env.WEBHOOK_SECRET
);
if (!isValid) {
return res.status(401).send('Invalid signature');
}
// Process webhook...
});Retry Behavior
Failed deliveries are retried automatically:
| Attempt | Delay | Total Time |
|---|---|---|
| 1 | Immediate | 0s |
| 2 | 60s | 1min |
| 3 | 120s | 3min |
| 4 | 300s | 8min |
Retry count and intervals are configurable per webhook.
Failure Conditions
A delivery is considered failed if:
- HTTP status code is not 2xx
- Connection timeout (30 seconds)
- SSL/TLS error
- DNS resolution failure
Delivery Logs
View webhook delivery history in the dashboard:
- Go to Repository Settings → Webhooks
- Click on a webhook
- View Recent Deliveries
Each delivery shows:
- Event type
- HTTP status code
- Response time
- Request/response body
- Retry attempts
API Reference
List Webhooks
GET /api/v1/code/repos/{org}/{repo}/webhooks
# Response
{
"webhooks": [
{
"id": "webhook_xxx",
"url": "https://example.com/webhook",
"events": ["push", "pull_request.opened"],
"isActive": true,
"deliveryCount": 42,
"failureCount": 2,
"lastDeliveryAt": "2024-01-01T00:00:00Z"
}
]
}Create Webhook
POST /api/v1/code/repos/{org}/{repo}/webhooks
Content-Type: application/json
{
"url": "https://example.com/webhook",
"secret": "my-secret",
"events": ["push", "pull_request.opened", "pull_request.merged"],
"maxRetries": 5,
"retryIntervalSeconds": 30
}Update Webhook
PATCH /api/v1/code/repos/{org}/{repo}/webhooks/{id}
Content-Type: application/json
{
"isActive": false
}Delete Webhook
DELETE /api/v1/code/repos/{org}/{repo}/webhooks/{id}Test Webhook
POST /api/v1/code/repos/{org}/{repo}/webhooks/{id}/testGet Deliveries
GET /api/v1/code/repos/{org}/{repo}/webhooks/{id}/deliveries
# Response
{
"deliveries": [
{
"id": "delivery_xxx",
"event": "push",
"status": "success",
"responseCode": 200,
"durationMs": 150,
"attempt": 1,
"deliveredAt": "2024-01-01T00:00:00Z"
}
]
}Redeliver
POST /api/v1/code/repos/{org}/{repo}/webhooks/{id}/deliveries/{deliveryId}/redeliverPlan Limits
| Plan | Max Webhooks | Retention |
|---|---|---|
| Free | 3 per repo | 7 days |
| Pro | 20 per repo | 30 days |
| Enterprise | Unlimited | 90 days |