Statly Code
Webhooks

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:

  1. Payload URL: The endpoint to receive events
  2. Secret: Optional shared secret for signature verification
  3. Events: Which events trigger the webhook

Test Webhook

Click Test to send a ping event and verify your endpoint.

Webhook Configuration

SettingDescriptionDefault
urlHTTPS endpoint to receive payloadsRequired
secretSecret for HMAC signatureOptional
contentTypePayload formatapplication/json
eventsArray of event typesRequired
isActiveEnable/disable webhooktrue
maxRetriesRetry count on failure3
retryIntervalSecondsSeconds between retries60

Event Types

Repository Events

EventDescription
pushCommits pushed to any branch
createBranch or tag created
deleteBranch or tag deleted
releaseRelease created or updated

Pull Request Events

EventDescription
pull_request.openedNew PR created
pull_request.closedPR closed (merged or not)
pull_request.mergedPR merged
pull_request.updatedPR updated (new commits, title change)
pull_request.review_requestedReview requested
pull_request.review_submittedReview submitted

Issue Events

EventDescription
issue.openedNew issue created
issue.closedIssue closed
issue.updatedIssue updated
issue.commentedNew comment on issue

CI Events

EventDescription
ci.run_startedCI run started
ci.run_completedCI run completed
ci.job_completedIndividual job completed

AI Review Events

EventDescription
ai_review.startedAI review started
ai_review.completedAI review completed
ai_review.suggestion_appliedAI 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:

AttemptDelayTotal Time
1Immediate0s
260s1min
3120s3min
4300s8min

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:

  1. Go to Repository Settings → Webhooks
  2. Click on a webhook
  3. 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}/test

Get 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}/redeliver

Plan Limits

PlanMax WebhooksRetention
Free3 per repo7 days
Pro20 per repo30 days
EnterpriseUnlimited90 days