Webhooks
Receive real-time HTTP notifications when events happen in your repositories, deployments, and CI/CD pipelines.
Configure a webhook endpoint to subscribe to events across your organization. When a subscribed event occurs, .git sends a POST request to your endpoint with a JSON payload containing event metadata and context.
Quick Setup
1. Generate a Secret
Create a x-git-signature secret to verify webhook authenticity. Store it securely in your environment variables.
2. Configure Your Endpoint
Provide an HTTPS URL that accepts POST requests with application/json payloads. Your endpoint must respond with a 2xx status code within 10 seconds.
3. Subscribe to Events
Select the event types you want to receive. You can subscribe to all events or filter by specific scopes like deployments, code_review, or issues.
Available Events
Select from the following event types when configuring your webhook:
🚀 deployment.success POST
Triggered when a deployment completes successfully.
⚠️ deployment.failed POST
Triggered when a deployment fails or rolls back.
📦 push.received POST
Triggered on new commits to subscribed branches.
👥 review.requested POST
Triggered when a PR review is requested or submitted.
🔐 secret.rotated POST
Triggered when environment variables are updated.
🌍 edge.cdn.purge POST
Triggered when the global edge cache is invalidated.
Payload Structure
Every webhook delivery includes a standardized JSON envelope. The data field contains event-specific details.
{
"id": "evt_8x7k2m9p4q",
"type": "deployment.success",
"timestamp": "2025-04-12T14:32:08Z",
"source": {
"organization": "acme-corp",
"repository": "backend-api",
"branch": "main"
},
"data": {
"deploy_id": "dpl_3n2m1k",
"url": "https://acme-api.git.dev",
"region": "us-east-1",
"duration_ms": 2430,
"commit_sha": "a1b2c3d4e5"
}
}
Common Payload Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique event identifier |
type | string | Event type (e.g., deployment.success) |
timestamp | ISO 8601 | Time the event occurred |
source | object | Context about the triggering resource |
data | object | Event-specific payload details |
Verification & Security
Every webhook request includes an X-Git-Signature-256 header containing an HMAC-SHA256 hex digest. Verify it to ensure requests originate from .git.
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const hmac = crypto.createHmac('sha256', secret);
const digest = hmac.update(payload).digest('hex');
const expected = `sha256=${digest}`;
// Constant-time comparison
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// Usage in Express
app.post('/webhook', (req, res) => {
const sig = req.headers['x-git-signature-256'];
if (!verifyWebhook(JSON.stringify(req.body), sig, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
res.status(200).send('OK');
});
import hashlib
import hmac
def verify_webhook(payload, signature, secret):
digest = hmac.new(
secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).hexdigest()
expected = f"sha256={digest}"
return hmac.compare_digest(signature, expected)
# Flask example
@app.route('/webhook', methods=['POST'])
def webhook():
sig = request.headers.get('X-Git-Signature-256')
if not verify_webhook(request.get_data(), sig, os.getenv('WEBHOOK_SECRET')):
return 'Invalid', 401
return 'OK', 200
# Simulate a webhook delivery locally
curl -X POST http://localhost:3000/webhook \
-H "Content-Type: application/json" \
-H "X-Git-Signature-256: sha256=8f14e45fceea167a5a36dedd4bea2543" \
-H "User-Agent: .git-Webhook/1.0" \
-d '{"type":"deployment.success","id":"evt_test","timestamp":"2025-04-12T14:32:08Z"}'
Delivery & Retries
.git guarantees at-least-once delivery. If your endpoint does not respond with a 2xx status, we retry with exponential backoff:
- 1st retry: 30 seconds
- 2nd retry: 2 minutes
- 3rd retry: 10 minutes
- 4th retry: 1 hour
- 5th retry: 6 hours
200 OK even if you process the payload asynchronously. Long-running sync processing will cause timeout retries.
Testing Locally
Use ngrok or localhost.run to expose your local development server to the public internet, then configure the generated URL as your webhook endpoint in the .git Dashboard.
# Start ngrok on port 3000 ngrok http 3000 # Copy the forwarding URL (e.g., https://a1b2c3.ngrok.io) # Configure it in .git -> Settings -> Webhooks