Features

Webhooks

secr can send HTTP notifications when secrets change. Use webhooks to trigger deployments, sync secret stores, or send alerts. Secret values are never included in payloads.

Events

Subscribe to one or more of the following events when creating a webhook:

EventTrigger
secret.createdA new secret is created
secret.updatedAn existing secret is updated
secret.deletedA secret is deleted
secret.promotedSecrets are promoted between environments
secret.bulk_setSecrets are bulk imported

Payload Format

All webhook payloads share this shape. Secret values are never included.

payload.json
{
  "event": "secret.created",
  "timestamp": "2024-01-15T12:00:00.000Z",
  "org": { "id": "uuid" },
  "project": { "id": "uuid", "slug": "my-project" },
  "environment": { "id": "uuid", "slug": "production" },
  "key": "DATABASE_URL",
  "actor": { "id": "uuid", "email": "user@example.com" },
  "metadata": {}
}

Headers

Every webhook delivery includes the following headers:

HeaderDescription
X-Secr-Signaturesha256={hmac} — HMAC-SHA256 of the raw body using your signing secret
X-Secr-EventEvent name (e.g. secret.created)
Content-Typeapplication/json

HMAC Verification

Always verify the X-Secr-Signature header before processing a webhook payload. Use a timing-safe comparison to prevent timing attacks.

Node.js

verify.js
import { createHmac, timingSafeEqual } from "node:crypto";

function verifyWebhook(body, signatureHeader, secret) {
  const expected = createHmac("sha256", secret)
    .update(body)
    .digest("hex");
  const received = signatureHeader.replace("sha256=", "");
  return timingSafeEqual(
    Buffer.from(expected, "hex"),
    Buffer.from(received, "hex"),
  );
}

Python

verify.py
import hashlib
import hmac

def verify_webhook(body: bytes, signature_header: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(), body, hashlib.sha256
    ).hexdigest()
    received = signature_header.replace("sha256=", "")
    return hmac.compare_digest(expected, received)

API Endpoints

All endpoints require admin or owner role.

MethodPathDescription
GET/v1/webhooks/:orgIdList webhooks
POST/v1/webhooks/:orgIdCreate webhook (returns signing secret)
GET/v1/webhooks/:orgId/:webhookIdGet webhook + recent deliveries
PATCH/v1/webhooks/:orgId/:webhookIdUpdate webhook
DELETE/v1/webhooks/:orgId/:webhookIdDelete webhook
POST/v1/webhooks/:orgId/:webhookId/testSend a test ping

Scoping

Webhooks are org-wide by default. Optionally scope to a specific project and/or environment when creating:

scoped-webhook.json
{
  "url": "https://example.com/hook",
  "events": ["secret.updated"],
  "projectId": "uuid",
  "environmentId": "uuid"
}

A scoped webhook only fires for events matching its project and environment filters.

Delivery Logs

Each webhook delivery is logged with status code, success flag, and response time. View the last 20 deliveries via the GET /v1/webhooks/:orgId/:webhookId endpoint or the dashboard.

Timeouts & Retries

BehaviorDetail
Timeout5-second timeout per delivery
RetriesFire-and-forget -- no automatic retries
FailuresFailed deliveries are logged for debugging

Start using webhooks

Create your first webhook from the dashboard or API.