Werkmail Docs
Contents

Guides

Webhooks

Werkmail POSTs a JSON envelope to your HTTPS URL when message or suppression events occur. URLs must be public HTTPS (SSRF-guarded). Secrets are shown once (whsec_…).

Create a subscription

bash
curl -sS -X POST -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ops",
    "url": "https://example.com/hooks/werkmail",
    "events": [
      "message.delivered",
      "message.hard_bounced",
      "message.spam_complaint",
      "message.failed",
      "message.content_blocked",
      "suppression.added"
    ]
  }' \
  "$BASE/api/practices/$PRACTICE_ID/webhooks"

List, delete, test, and inspect deliveries:

  • GET /api/practices/{id}/webhooks
  • DELETE /api/practices/{id}/webhooks/{webhookID}
  • POST /api/practices/{id}/webhooks/{webhookID}/test
  • GET /api/practices/{id}/webhooks/{webhookID}/deliveries

Envelope

json
{
  "id": "delivery-uuid",
  "event": "message.delivered",
  "timestamp": "2026-08-21T12:00:00Z",
  "data": {
    "message_id": "…",
    "status": "delivered"
  }
}

Headers

Header Meaning
Content-Type application/json
X-Werkmail-Event Event name
X-Werkmail-Timestamp Unix seconds
X-Werkmail-Signature Hex HMAC-SHA256 of {timestamp}.{body} using the webhook secret
User-Agent werkmail-webhooks/1.0

Verify in constant time. Reject timestamps older than a few minutes to stop replays.

python
import hmac, hashlib

def valid(secret: str, timestamp: str, body: bytes, signature_hex: str) -> bool:
    mac = hmac.new(secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256)
    return hmac.compare_digest(mac.hexdigest(), signature_hex.lower())

Event names

Message: message.created, message.sent, message.delivered, message.opened, message.clicked, message.hard_bounced, message.soft_bounced, message.auto_replied, message.spam_complaint, message.failed, message.content_blocked, message.suppressed, message.unsubscribed, message.delivery_delayed, message.subscription.

Suppression: suppression.added, suppression.removed (include scope, project_id, route_id, and slugs when known).

Test: webhook.test.

Open, click, and delay events require open/click tracking on the route or send settings.

Slack / Teams alerts

POST /api/practices/{id}/alerts with kind slack or teams and a public incoming-webhook URL. Default events: hard bounce, soft bounce, complaint, content blocked, failed send.

View this page as Markdown · llms.txt · full corpus