Skip to content

Webhooks

A webhook delivers every domain event to an HTTPS endpoint you control.

bash
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:

php
$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:

EventEmitted when
contact.created / contact.updated / contact.deletedA contact changes
contact.unsubscribed / contact.resubscribedSuppression changes
form.submittedA hosted form receives a submission
email.delivered / email.failedA worker finishes a send
channel_message.sent / channel_message.failedA 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.

Released under the Apache 2.0 License.