Skip to main content

Webhooks

Webhooks push notification events to your own systems as they happen: Hober sends an HTTPS POST to your endpoint the moment a subscriber is created, a send is dispatched, a campaign finishes, or a recipient interacts with a message. This is the same REST-hook surface that powers the Zapier integration — anything Zapier can react to, your own automation can too.

Plan availability

Webhooks are a plan feature. On plans without it, webhook endpoints cannot be created and the API responds 403 with "error": "feature_not_available". Each workspace can have up to 10 webhook endpoints.


1. Creating an endpoint

In the dashboard

Open Settings → Webhooks ("Receive HTTP callbacks when notification events occur."):

  1. Click Add webhook, enter your Endpoint URL (must be HTTPS), and tick the event types you want.
  2. On save, the endpoint's signing secret (whsec_…) is shown once — store it now; it cannot be retrieved later.
  3. Each endpoint row shows its subscribed events and offers Test (fires a test delivery to your URL) and Delete. A delivery log panel below shows recent webhook deliveries so you can debug your receiver.

Via the API

The REST-hook API authenticates with a server key (hober_srv_…, from Settings → API Keys → Server keys):

POST /v1/hooks
Authorization: Bearer hober_srv_...
Content-Type: application/json

{
"target_url": "https://example.com/webhooks",
"events": ["subscriber.created", "notification.terminal"]
}

A 201 response returns the endpoint — including the signing secret, this one time only:

{
"id": "hook-uuid",
"target_url": "https://example.com/webhooks",
"events": ["subscriber.created", "notification.terminal"],
"secret": "whsec_..."
}

Related endpoints:

Method & pathPurpose
GET /v1/hooksList your endpoints (secrets omitted).
DELETE /v1/hooks/:idRemove an endpoint.
GET /v1/hooks/samples/:eventReturns a one-element array of sample payload data for an event type — handy when building an integration before real traffic exists.

The target URL must be a valid HTTPS URL, and every requested event type must be one of the known types below — anything else is rejected with a 422 validation error.


2. Event types

Event typeFires when
subscriber.createdA net-new subscriber is created (updates to existing subscribers do not re-fire).
notification.dispatchedA notification job is dispatched for sending.
notification.terminalA job reaches a terminal state (completed or failed) — final delivery counts included.
notification.interactionA recipient interacts with a message: tap, open, click, dismiss, and so on.

notification.interaction can be high-volume — one event per recipient interaction. Subscribe an endpoint to it deliberately.


3. Payloads

Every delivery is a JSON POST with a common envelope; the data field carries the event-specific payload:

{
"id": "delivery-uuid",
"event_type": "notification.terminal",
"tenant_id": "tenant-uuid",
"timestamp": "2026-07-27T12:00:00Z",
"data": { }
}

subscriber.created

{
"subscriber_id": "0f8e7d6c-5b4a-4392-8171-6e5d4c3b2a19",
"external_id": "user-1042",
"email": "ana@example.com",
"attributes": { "plan": "growth", "first_name": "Ana" },
"created": true
}

notification.dispatched

{
"job_id": "job-uuid",
"target_size_estimate": 5000,
"scheduled_at": "2026-07-27T12:00:00Z"
}

notification.terminal

{
"job_id": "job-uuid",
"status": "completed",
"delivered": 1180,
"failed": 20,
"total": 1200
}

status is "completed" or "failed".

notification.interaction

{
"job_id": "job-uuid",
"interaction_type": "tapped",
"platform": "ios",
"variant_id": "variant-uuid"
}
  • interaction_type is one of: foreground_received, tapped, action_tapped, dismissed, email_opened, email_clicked, inapp_impression, inapp_click, inapp_dismiss.
  • platform is one of: ios, android, web, email, server.
  • variant_id is present only for A/B variant sends.

4. Delivery, retries, and headers

Each delivery POSTs the JSON body with these headers:

HeaderValue
Content-Typeapplication/json
X-Hober-EventThe event type, e.g. notification.terminal.
X-Hober-DeliveryA unique delivery ID (UUID) — use it for idempotency if you receive a retry.
X-Hober-Signaturesha256= followed by a hex HMAC of the body (see below).

Delivery semantics:

  • A response with status 200–299 counts as delivered. Respond quickly (do heavy work asynchronously) — each attempt has a 10-second timeout.
  • On a 5xx response or a network error, delivery is retried up to 3 more times with backoff of 1s, 2s, then 4s (4 attempts total).
  • A 4xx response is treated as a permanent failure for that delivery and is not retried.
  • Every attempt is recorded; the dashboard's webhook delivery log shows the payload, attempt count, last status code, and outcome per delivery, and each endpoint tracks its consecutive-failure count.

5. Verifying signatures

Always verify X-Hober-Signature before trusting a payload. The signature is an HMAC-SHA256 over the raw request body. The HMAC key is not the secret itself but the hex-encoded SHA-256 digest of your whsec_… secret string:

key = hex( SHA-256( "whsec_..." ) ) // your stored secret, hashed once
expected = "sha256=" + hex( HMAC-SHA256(key, raw_body) )

For example, in Go:

sum := sha256.Sum256([]byte(secret)) // secret = "whsec_..."
key := hex.EncodeToString(sum[:])

mac := hmac.New(sha256.New, []byte(key))
mac.Write(body) // raw request body bytes
expected := "sha256=" + hex.EncodeToString(mac.Sum(nil))

valid := hmac.Equal([]byte(expected), []byte(r.Header.Get("X-Hober-Signature")))

Compare with a constant-time comparison, and reject the request if the signature does not match.


6. Notes

  • Zapier: the Zapier app's instant triggers (New Subscriber, Campaign Finished) are built on exactly these hooks.
  • Slack summaries are a separate feature: the Slack integration posts formatted campaign summaries to a Slack channel and is configured independently — it is not part of the webhook surface described here.
  • Sending data in: webhooks are outbound. To push events into Hober (for segments, journey triggers, and personalization), use the Events API with the same server key — see Server-Side Event Tracking.