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.
| Integration | Delivers | Where |
|---|---|---|
| SikkerKey | Signed JSON, verifiable with an HMAC-SHA256 signature | Your own HTTPS endpoint |
| Discord | A rich message, color-coded by severity | A Discord channel |
| Slack | A rich message, color-coded by severity | A 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.
- Choose an integration: SikkerKey, Discord, or Slack.
- Set the destination. For SikkerKey, enter your HTTPS endpoint URL. For Discord or Slack, paste the incoming-webhook URL from your channel's settings.
- 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.
- 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:
| Header | Value |
|---|---|
X-SikkerKey-Delivery-Id | Unique UUID for this delivery, use for deduplication |
X-SikkerKey-Signature | HMAC-SHA256 hex digest of the request body |
X-SikkerKey-Event | The action name (e.g. secret_create) |
User-Agent | SikkerKey-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:
| Field | Description |
|---|---|
type | user, machine, ai_agent, system, or external |
name | The actor's display name, such as a username, machine name, or AI-agent name |
id | The 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_testevent 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.