Deploy Webhooks
Webhooks let Vessl notify an external URL when something happens to your app — a deploy starts, succeeds, or fails, or the app is started/stopped. Use them to trigger CI pipelines, send Slack messages, invalidate CDN caches, or integrate with any HTTP-capable service.
Adding a webhook
- Open your app and go to Settings → Webhooks.
- Click Add Webhook.
- Enter the URL to call (must be
http://orhttps://, public internet only). - Select the events to subscribe to.
- Optionally enter a secret for signature verification.
- Click Save.
You can add multiple webhooks per app, each subscribed to different events.
Events
| Event | When it fires |
|---|---|
deployment.started | A deploy job begins |
deployment.success | Deploy completes and the app is healthy |
deployment.failed | Deploy fails at any phase |
app.started | App is manually started |
app.stopped | App is manually stopped |
webhook.test | When you click Send Test in the dashboard |
Payload
Every webhook call is a POST request with Content-Type: application/json. The body shape:
{
"event": "deployment.success",
"application_id": "019...",
"timestamp": "2026-06-23T10:00:00+00:00",
"payload": {
"deployment_id": "019...",
"commit_sha": "abc1234",
"branch": "main"
}
}
The payload fields vary by event:
| Event | Payload fields |
|---|---|
deployment.started | deployment_id, branch |
deployment.success | deployment_id, commit_sha, branch |
deployment.failed | deployment_id, reason |
app.started / app.stopped | (empty) |
webhook.test | message |
Verifying webhook signatures
If you set a secret when creating the webhook, Vessl includes a X-Vessl-Signature header on every request:
X-Vessl-Signature: sha256=<hmac-sha256 of the raw request body>
Verify it in your handler to confirm the request came from Vessl and wasn't tampered with:
// Node.js example
const crypto = require('crypto');
function verifySignature(body, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
# Python example
import hmac, hashlib
def verify_signature(body: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Always use a timing-safe comparison (timingSafeEqual / compare_digest) to prevent timing attacks.
Testing a webhook
From Settings → Webhooks, click Test next to any webhook. Vessl sends a webhook.test event to the URL immediately. The response status and any error are shown in the dashboard.
Webhook delivery
- Vessl makes one attempt per event — there is no automatic retry on failure.
- The request times out after 10 seconds. Make sure your handler responds quickly; defer heavy work to a background queue.
- Redirects are not followed (to prevent SSRF via open redirects). Your endpoint must respond at the exact URL configured.
- The webhook URL must resolve to a public IP. Private, loopback, and link-local addresses (RFC 1918,
169.254.x.x, etc.) are blocked.