Skip to content
Sendora Cloud
Create account
Operate

Webhooks

Send Sendora-originated events to your endpoints with HMAC signature + retry + SSRF guard + dead-letter on persistent failure.

Features

  • **One subscription, whole taxonomy** — 50+ canonical event types across auth, push, email, sms, links, surveys, automation, billing, support, csat, consent, attribution. Customer subscribes once + their mirror stays in sync.
  • **HMAC-SHA256 signing** — `t=…,v1=…` header (Stripe convention) so SDKs your team already wrote against Stripe slot in unchanged.
  • **Exponential backoff** (2s / 8s / 30s / 90s) + permanent-vs-transient HTTP status classification — 4xx (except 408/429) goes permanent fast; 5xx / network / 429 retry.
  • **Per-endpoint event filters** — subscribe to `auth.*` only, `email.bounced` only, whatever. Multiple endpoints per org, each with its own filter.
  • **Delivery log + one-click replay** — every attempt logged with status code + response body + reconstructed signed-header line. Failed deliveries replay individually or in bulk by event filter.
  • **Inbound endpoints with SSRF guard** — accept provider callbacks (Stripe, GitHub, Slack) without standing up your own validator stack. `lib/url-safety.ts` blocks RFC1918, loopback, link-local, cloud-metadata IPs (169.254.169.254, etc.), CGN ranges. Replay-window guard built in.
  • **Rotating signing secret** — endpoint can hold two active secrets during rotation, both verify, then retire the old one. No webhook outage during key rotation.

Common use cases

  • Replace Svix ($490+/mo Pro) — the delivery posture is identical (HMAC + exp backoff + replay), the event source ships with it.
  • Replace Hookdeck (~$200/mo Mid) — same posture, plus you don't have to ship product events into it first.
  • Mirror Sendora identity / messaging / support into your DB — `auth.device_takeover` deletes the right row, `email.bounced` updates the right user trait, `csat.detractor` flags the right account.
  • Accept Stripe / GitHub / Slack callbacks without a separate validator service.
  • Cross-tool wiring — Slack alerts on detractor CSAT, Discord pings on ticket SLA breach, PagerDuty on auth.signin_storm.

Key concepts

HMAC signature
`X-Sendora-Signature: sha256=<hex>` over the raw body. Verify server-side before trusting payload.
Retry policy
Exponential backoff, 6 attempts over ~30 min. Persistent fails go to dead-letter — visible in dashboard.
SSRF guard
URL allowlist + RFC1918 / loopback / cloud-metadata block. Kill-switch `SSRF_GUARD=off`.

Webhooks

Create a webhook

FREE

POSTs the event JSON to your URL on every matching event. Returns a `secret` (one-time reveal) used to sign the `X-Sendora-Signature` header.

curl -X POST https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/webhooks/endpoints \
  -H "x-api-key: pk_prod_…" \
  -d '{
    "url": "https://your-app.com/hooks/sendora",
    "events": ["email.delivered", "email.bounced", "auth.user_signed_up"]
  }'

# Response includes "secret" — store it to verify signatures.

Verify the signature

FREE

HMAC-SHA256 of the raw request body using your webhook secret. Compare in constant time to defend against timing attacks.

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, signature: string, secret: string) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

Retry + backoff

FREE

Failed deliveries (non-2xx, timeout, network error) retried in-process with exponential backoff over ~2 minutes (5 attempts including the initial fire). Final failure logged + visible in the Recent deliveries panel; Retry button on the dashboard re-fires a one-off attempt.

# No SDK call — automatic.
# Backoff schedule: initial fire, then 2s, 8s, 30s, 90s. Endpoints
# returning 2xx within ~2min won't see a final-failure log.

Fire a test event

FREE

Send a synthetic event to verify your handler. Same signature flow as production events.

curl -X POST https://api.sendoracloud.com/api/v1/orgs/<ORG_UUID>/dev-tools/webhook-test \
  -H "x-api-key: pk_prod_…" \
  -d '{ "url": "https://your-app.com/hooks/sendora", "event": "email.delivered" }'

Related