Event Webhooks
Event Webhooks
Event Webhooks deliver real-time HTTP callbacks when subscriber events occur. Configure one or more endpoints per domain to receive structured event data as it happens.
Configuration
Navigate to Domain Settings → Event Webhooks to create, edit, or archive webhook endpoints.
Each webhook specifies:
URL: the destination endpoint
Headers: custom headers, with optional Liquid macros for secrets
Events: one or more event types to subscribe to
All deliveries are POST with a JSON body containing the full event payload.

Supported Events
Notification
notification.displayed
A subscriber's device renders a notification
Notification
notification.clicked
A subscriber clicks a notification
Each event fires once per subscriber per action. A notification sent to 10,000 subscribers produces up to 10,000 individual events.
Payload Structure
Fixed envelope with event-specific data. Null fields are omitted.
Envelope
version
int
Payload schema version
event_type
string
Dot-namespaced event identifier (e.g. notification.clicked)
event_id
string (UUID)
Stable identifier for this event. Use as your deduplication key.
event_timestamp
string (ISO 8601, UTC)
When the event occurred
domain
object
The Pushly domain the event belongs to
user
object
The subscriber who triggered the event
data
object
Event-specific content. Contains exactly one key matching the event subject.
The data object contains a single key matching the event's subject. For notification.* events, that key is notification.
All timestamps are ISO 8601 UTC with millisecond precision.
Header Macros
Custom header values support Liquid template syntax for referencing stored domain secrets:
Only secrets explicitly referenced in header templates are loaded. System-managed secrets (aliases starting with _) are not accessible in templates.
Headers
Every delivery includes:
X-Pushly-Webhook-Id
UUID identifying which webhook config produced this delivery
X-Pushly-Event-Id
The unique event ID from the payload. Use for deduplication.
X-Pushly-Signature
HMAC-SHA256 signature of the request body (see below)
X-Pushly-Delivery-Timestamp
Unix timestamp (seconds) when the delivery was initiated
X-Pushly-Attempt-Number
1-indexed attempt number
Content-Type
application/json
Reserved header names (Content-Type, Host, Content-Length, Transfer-Encoding, anything starting with X-Pushly-) cannot be overridden by custom headers in your webhook configuration.
Signature Verification
Every delivery includes an X-Pushly-Signature header for authenticity verification.
Format: sha256=<hex_digest>
Verification algorithm:
Encode your signing secret as UTF-8 bytes
Compute HMAC-SHA256 over the raw request body using the secret as the key
Hex-encode the digest
Compare to the value after
sha256=in the header using constant-time comparison
Important: Verify against the raw request body, not a parsed and re-serialized version. JSON key ordering and whitespace affect the digest.
Replay prevention (optional): Compare X-Pushly-Delivery-Timestamp to your server's current time. Reject deliveries older than your tolerance window (e.g. 5 minutes).
Your signing secret is available in Domain Settings → Event Webhooks → Signing Secret.
Idempotency
Pushly produces one event per subscriber per action. Events may be delivered more than once if your endpoint fails or times out — use event_id for deduplication, and use a durable queue on your side if processing happens asynchronously after acknowledgment.
Delivery
Timeout
Your endpoint must respond within 5 seconds. Acknowledge immediately and process asynchronously if your logic takes longer.
Retries
1
Immediate
2
4 seconds after first failure
3
16 seconds after second failure
After 3 attempts, the event moves to a dead-letter queue.
Retried: HTTP 5xx, timeouts, connection errors. Not retried: HTTP 4xx, SSRF blocks.
Ordering
Events may arrive out of order. Use event_timestamp for chronological ordering, not delivery order.
Network Security
The primary authentication mechanism for webhook deliveries is HMAC signature verification (above). Every delivery includes an X-Pushly-Signature header you can validate against the request body using your signing secret. This is cryptographic proof the request came from Pushly — independent of network origin and resilient to infrastructure changes on our side.
IP Allowlisting
We don't publish a static list of egress IPs. If your security or compliance policy requires IP-based network controls, contact your Pushly account manager to discuss your requirements.
TLS
Webhook endpoints must be reachable over HTTPS. Pushly does not deliver to plain HTTP URLs. We require TLS 1.2 or higher and validate your endpoint's certificate against standard public certificate authorities. Self-signed certificates are not supported.
SSRF Protection
Pushly validates every destination URL against private and reserved IP ranges before connecting. Requests to private (RFC 1918), loopback, link-local, and instance-metadata addresses are rejected.
Versioning
New fields and event types are added without incrementing version. Ignore unknown fields in your handlers.
Breaking changes (field removals or renames) increment version with a deprecation window.
Last updated