Webhooks

Deliver real-time vault events to your own endpoint, Discord, or Slack.

Webhooks deliver vault events to an integration you choose. Point them at your own HTTPS endpoint to receive signed JSON, or at a Discord or Slack channel to receive a formatted message the moment a subscribed action fires.

Webhooks are available on every plan. The number of webhooks you can create and the daily delivery limit depend on your plan; check the pricing page for details.

Integrations

Each webhook uses one integration, chosen when you create it.

IntegrationDeliversWhere
SikkerKeySigned JSON, verifiable with an HMAC-SHA256 signatureYour own HTTPS endpoint
DiscordA rich message, color-coded by severityA Discord channel
SlackA rich message, color-coded by severityA Slack channel

The SikkerKey integration issues a signing secret so your server can verify each delivery. Discord and Slack deliver to your channel using the incoming-webhook URL from that channel's settings.

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 flow.

  1. Choose an integration: SikkerKey, Discord, or Slack.
  2. Set the destination. For SikkerKey, enter your HTTPS endpoint URL. For Discord or Slack, paste the incoming-webhook URL from your channel's settings.
  3. 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.
  4. Review and create.

For the SikkerKey integration, the signing secret is displayed once the webhook is created. Save it now. You can also reveal it again later from the webhook's settings panel (see Managing Webhooks below). You need this secret to verify webhook signatures on your server.

Payload Format

The SikkerKey integration delivers each event as 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": {
    "actor": { "type": "machine", "name": "web-prod-01", "id": "..." },
    "secretId": "sk_abc123",
    "sourceIp": "203.0.113.42",
    "detail": "Secret deleted: production-api-key"
  }
}

data.actor names who performed the action:

FieldDescription
typeuser, machine, ai_agent, system, or external
nameThe actor's display name, such as a username, machine name, or AI-agent name
idThe actor's identifier, for correlation. Null for system and external events

The remaining data fields appear only when relevant to the event: secretId for secret events, sourceIp for the request origin, and detail for a human-readable summary.

Discord and Slack deliveries carry the same event information, formatted for the channel rather than as this JSON.

Verifying Signatures

Signatures apply to the SikkerKey integration. 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 the destination is reachable.
  • Configure: Change the destination URL or the subscribed events. The signing secret is unchanged.
  • Reveal signing secret (SikkerKey integration): From the settings 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 integration and destination 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.