Webhooks
A webhook delivers every domain event to an HTTPS endpoint you control.
curl -X POST http://api.localhost/v1/webhooks \
-H "X-API-Key: $NOTIFYZR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "url": "https://example.com/hooks/notifyzr" }'The response includes a signing secret. Store it — it is how you verify that a delivery came from Notifyzr.
Verifying a delivery
Each request carries an HMAC-SHA256 signature of the raw body, computed with the webhook's secret. Verify against the raw bytes, before any JSON parsing:
$expected = hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expected, $request->getHeaderLine('X-Notifyzr-Signature'))) {
http_response_code(401);
return;
}Use a constant-time comparison, not ==.
Events
Events are named resource.verb:
| Event | Emitted when |
|---|---|
contact.created / contact.updated / contact.deleted | A contact changes |
contact.unsubscribed / contact.resubscribed | Suppression changes |
form.submitted | A hosted form receives a submission |
email.delivered / email.failed | A worker finishes a send |
channel_message.sent / channel_message.failed | A Discord/Telegram push finishes |
The same catalog drives automations — an integration you build and an automation a user configures react to exactly the same events.
Delivery
Deliveries are queued, not made inline with the request that caused them: a slow endpoint of yours never slows the API call that triggered it. Failures are retried with exponential backoff, and exhausted retries land in a dead-letter queue.
Emitting is best-effort by design — if the broker is unavailable, the failure is logged and the originating request still succeeds. Notifyzr will not fail a customer's send because your webhook endpoint was unreachable.