Quick take
A webhook endpoint should acknowledge quickly, verify authenticity, store the raw event, dedupe by event or message ID, and update delivery state only when the event is newer or more final than what is already stored.
Webhook implementation checklist
Use this checklist before production traffic depends on webhook delivery.
| Requirement | Implementation note | Failure mode |
|---|---|---|
| Fast 2xx response | Authenticate, store, enqueue, and respond before slow downstream work. | Provider retries can pile up and duplicate events. |
| Signature validation | Validate with the exact URL, headers, and raw body rules required by the provider. | Forged or malformed callbacks can alter delivery state. |
| Raw payload storage | Persist raw body, headers, provider, received time, and parsed result. | Support cannot reconstruct what the provider actually sent. |
| Idempotency | Dedupe by provider event ID when available, otherwise by message ID plus status plus timestamp. | Duplicate callbacks create noisy timelines. |
| State ordering | Ignore stale events when a newer terminal state already exists. | Out-of-order events can move delivered messages back to sent or queued. |
Normalized payload shape
A Notilify-style normalized event should preserve provider detail while giving the app a stable state model. Keep fields such as messageId, providerMessageId, status, occurredAt, receivedAt, country, senderIdentity, errorCode, errorCategory, rawProvider, and rawPayloadId.
Do not assume every provider sends the same status names or certainty. Normalize for your app, but keep raw evidence for audits and support.
- accepted
- queued
- sent
- delivered
- failed
- undelivered
- expired
- unknown
Build webhook ingestion once
Notilify helps teams keep delivery events normalized, searchable, and useful for support.