Webhooks

Receiving real-time vault event notifications via signed HTTP payloads.

Webhooks deliver vault events to your own HTTP endpoints as signed JSON payloads. When a subscribed action fires, SikkerKey POSTs the event to your URL with an HMAC-SHA256 signature so you can verify authenticity.

Webhooks require a paid plan. The number of webhooks you can create and the daily delivery limit depend on your plan. Check the pricing page for details.

Creating a Webhook

From the dashboard, go to the Alerts page. The Webhooks card is at the top. Click the + button to open the create modal.

  1. Enter your endpoint URL. It must use HTTPS.
  2. Select which events to subscribe to. Events are grouped by category, the same set shown on the Alerts page. Use the search bar, severity filter, and category filter to find specific actions. Click a category checkbox to select all actions in that group.
  3. Click Create Webhook.

After creation, the signing secret is displayed. Save it now. You can also reveal it again later from the webhook's edit panel (see Managing Webhooks below). You need this secret to verify webhook signatures on your server.

Payload Format

Every webhook delivery is an HTTP POST with Content-Type: application/json and these headers:

HeaderValue
X-SikkerKey-Delivery-IdUnique UUID for this delivery, use for deduplication
X-SikkerKey-SignatureHMAC-SHA256 hex digest of the request body
X-SikkerKey-EventThe action name (e.g. secret_create)
User-AgentSikkerKey-Webhook/1.0

The JSON body:

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "event": "secret_delete",
  "severity": "high",
  "timestamp": 1712678400000,
  "data": {
    "userId": "...",
    "machineId": "...",
    "secretId": "sk_abc123",
    "sourceIp": "203.0.113.42",
    "detail": "Secret deleted: production-api-key"
  }
}

Fields in data are included only when relevant to the event. For example, machineId is null for events that don't involve a machine.

Verifying Signatures

Compute the HMAC-SHA256 of the raw request body using the signing secret you received at creation. Compare it to the X-SikkerKey-Signature header value.

import hmac, hashlib

def verify(body: bytes, secret: str, signature: str) -> bool:
    expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)
const crypto = require('crypto');

function verify(body, secret, signature) {
  const expected = crypto.createHmac('sha256', secret).update(body).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
func verify(body []byte, secret, signature string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write(body)
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signature))
}

Always use constant-time comparison to prevent timing attacks.

Deduplication

Every delivery includes a unique id (UUID) in the payload body and as the X-SikkerKey-Delivery-Id header. This ID stays the same across retries of the same delivery.

If your endpoint returns a success but the response doesn't reach SikkerKey (network issue, timeout), the same payload will be retried with the same id. Store processed delivery IDs on your end and skip duplicates.

Delivery Behavior

  • Timeout: Each delivery attempt has a 15-second timeout.
  • Retries: Failed deliveries are retried up to 3 times with exponential backoff (5 seconds, 30 seconds, 5 minutes).
  • Success: Any HTTP 2xx response is treated as successful.
  • Health tracking: Consecutive failures are tracked per webhook. After 10 consecutive failures, the webhook is automatically disabled.
  • Burst limiting: Outbound deliveries are globally rate-limited to 60 per second with burst capacity. This prevents high-activity events from overwhelming your endpoints.

Delivery Source IP

SikkerKey delivers every webhook from a single, stable egress address: 49.13.140.25. If your endpoint sits behind a firewall or IP allowlist, permit inbound HTTPS from this address. Deliveries always originate from this IP, never from SikkerKey's main API infrastructure, so you can scope your allowlist to exactly one address.

Managing Webhooks

From the Webhooks card on the Alerts page:

  • Test: Sends a test payload (webhook_test event with info severity) to verify your endpoint is reachable.
  • Edit: Change the endpoint URL or the subscribed events. The signing secret is unchanged.
  • Reveal signing secret: From the edit panel, reveal the current signing secret (masked by default) and copy it, for when it wasn't saved at creation. Each reveal is recorded in your audit log.
  • Disable / Enable: Toggles the webhook without deleting it. Re-enabling resets the health status and failure counter.
  • Delete: Permanently removes the webhook.

Each webhook row shows:

  • The endpoint URL
  • Health status: healthy, unhealthy, or disabled
  • Number of subscribed events
  • Last successful delivery time
  • Consecutive failure count (if any)
  • Last error message (if any)

Plan Limits

Your plan determines two webhook limits:

  • Webhook endpoints: the maximum number of webhooks you can create.
  • Daily deliveries: the maximum number of webhook payloads delivered per day, resetting at midnight UTC.

The Alerts page header shows your deliveries used today, your daily limit, and when the count resets, so the day's remaining budget is visible at a glance.

When the daily delivery limit is reached, remaining deliveries for the day are silently dropped. The webhook remains healthy -- deliveries resume the next day.