Skip to main content

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

  1. Open your app and go to Settings → Webhooks.
  2. Click Add Webhook.
  3. Enter the URL to call (must be http:// or https://, public internet only).
  4. Select the events to subscribe to.
  5. Optionally enter a secret for signature verification.
  6. Click Save.

You can add multiple webhooks per app, each subscribed to different events.

Events

EventWhen it fires
deployment.startedA deploy job begins
deployment.successDeploy completes and the app is healthy
deployment.failedDeploy fails at any phase
app.startedApp is manually started
app.stoppedApp is manually stopped
webhook.testWhen 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:

EventPayload fields
deployment.starteddeployment_id, branch
deployment.successdeployment_id, commit_sha, branch
deployment.faileddeployment_id, reason
app.started / app.stopped(empty)
webhook.testmessage

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.