Skip to main content
When an event fires, Sevalla sends a POST request to your webhook endpoint with a JSON payload. This page documents what your endpoint receives and how to verify it.

Payload structure

Every webhook request body follows this format:
{
  "webhook_id": "d5f8a1c2-3b4e-5f6a-7b8c-9d0e1f2a3b4c",
  "event_id": "a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "event_delivery_id": "f1e2d3c4-b5a6-9788-9a0b-c1d2e3f4a5b6",
  "type": "APP_DEPLOY",
  "data": {}
}
FieldTypeDescription
webhook_idstringUUID of the webhook that triggered this delivery.
event_idstringUUID of the event. Same across retries.
event_delivery_idstringUUID of this specific delivery attempt. Unique per retry.
typestringThe event type. See Event types below.
dataobjectEvent-specific payload. Shape depends on type.

Request headers

Sevalla sends two headers with every webhook request:
HeaderValue
content-typeapplication/json
svl-signatureYour webhook secret (e.g. whsec_...).

Verifying signatures

Every webhook request includes an svl-signature header containing your webhook’s secret. Compare this value against the secret stored on your end to verify the request is from Sevalla.
import { type IncomingMessage } from "node:http";

function verifyWebhook(req: IncomingMessage, secret: string): boolean {
  const signature = req.headers["svl-signature"];
  return signature === secret;
}
Always verify the svl-signature header before processing a webhook. Without verification, anyone who discovers your endpoint URL could send fake events.

Event types

You can subscribe to any combination of these events when creating a webhook.

Application events

TypeFires when
APP_CREATEAn application is created.
APP_UPDATEAn application is modified.
APP_DELETEAn application is deleted.
APP_DEPLOYA deployment starts, succeeds, or fails.
APP_CREATE, APP_UPDATE, APP_DELETE data:
{
  "id": "app-id",
  "company_id": "company-id",
  "name": "my-app",
  "display_name": "My App",
  "location": "eu-west"
}
APP_DEPLOY data:
{
  "company_id": "company-id",
  "app_id": "app-id",
  "app_name": "my-app",
  "app_display_name": "My App",
  "deployment_id": "deploy-id",
  "status": "success",
  "commit": "a1b2c3d",
  "stage": "production",
  "is_preview": false
}

Static site events

TypeFires when
STATIC_SITE_CREATEA static site is created.
STATIC_SITE_UPDATEA static site is modified.
STATIC_SITE_DELETEA static site is deleted.
STATIC_SITE_DEPLOYA static site deployment starts, succeeds, or fails.
STATIC_SITE_CREATE, STATIC_SITE_UPDATE, STATIC_SITE_DELETE data:
{
  "id": "site-id",
  "company_id": "company-id",
  "name": "my-site",
  "display_name": "My Site"
}
STATIC_SITE_DEPLOY data:
{
  "company_id": "company-id",
  "static_site_id": "site-id",
  "static_site_name": "my-site",
  "static_site_display_name": "My Site",
  "deployment_id": "deploy-id",
  "status": "success",
  "repo_url": "https://github.com/org/repo",
  "branch": "main",
  "commit": "a1b2c3d",
  "is_preview": false
}

Database events

TypeFires when
DATABASE_CREATEA database is created.
DATABASE_UPDATEA database is modified.
DATABASE_DELETEA database is deleted.

Retry behavior

If your endpoint returns a non-2xx status code or doesn’t respond, Sevalla retries the delivery up to 12 times with exponential backoff:
RetryDelay
11 minute
25 minutes
310 minutes
430 minutes
51 hour
62 hours
74 hours
88 hours
916 hours
101 day
112 days
123 days
Each retry generates a new event_delivery_id but keeps the same event_id. After 12 failed attempts, the delivery is marked as failed permanently.
Return a 200 status code as quickly as possible. Process the webhook payload asynchronously to avoid timeouts. If your endpoint is slow to respond, it may be treated as a failure.

Secret rotation

When you rotate a webhook secret, you can set a grace period (0-24 hours) during which both the old and new secrets are valid. During this window, the svl-signature header will contain the old secret. Once the grace period expires, only the new secret is used. This lets you deploy updated verification logic without missing events.