Webhooks
Signed work events, delivered to you.
Register an HTTPS destination with webhook_register(url, events_json, secret?). ZenSched rejects private, loopback, link-local, and reserved destinations.
Available events
worker.invitedworker.activatedshift.checkinshift.checkoutshift.missedtimesheet.readybilling.low_balancewebhook.disabledUse webhook_test to test delivery and webhook_deliveries to inspect attempts.
Verify every request
ZenSched sends X-ZenSched-Signature, X-ZenSched-Timestamp, and X-ZenSched-Event. The signature is a hexadecimal HMAC-SHA256 digest over exactly "{timestamp}.{raw_body}".
import hashlib, hmac
def valid_signature(secret, timestamp, raw_body, signature):
signed = f"{timestamp}.{raw_body.decode()}".encode()
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature) Payload envelope
{
"event": "shift.checkin",
"org_id": 123,
"event_id": 456,
"created_at": "2026-07-27T18:00:00Z",
"data": { }
} webhook_test uses a test payload with test: true and sent_at in place of the regular event identifiers.
Retries and disablement
- A 2xx response completes delivery. Each request has a 10-second timeout.
- Failures retry up to five times: 1 minute, 5 minutes, 15 minutes, 1 hour, then 3 hours.
- After 24 hours of continuous hard failures, ZenSched disables the webhook and sends a final
webhook.disabledevent where possible. - Organizations may register up to 10 webhook destinations.