Skip to Content
WebhooksIntroduction

Webhooks

Webhooks let your app react to email lifecycle events as they happen. Send → Delivery → Open → Click → Bounce → Complaint — every state transition fires an HTTP POST to your URL with a structured JSON payload.

How it works

  1. You create a configuration set (a logical grouping for sends).
  2. You add a webhook event destination to that config set, with the URL + secret + the event types you want.
  3. You send emails with configuration_set_name referencing that set.
  4. Every event for those sends gets POSTed to your URL with an HMAC-signed body.
  5. Retries: 5xx + timeout → 1min, 5min, 15min. 4xx → no retry (your URL is broken; we don’t waste retries).

Set up a webhook in 3 calls

1. Create a config set

curl https://apis.splashifypro.com/api/v1/partner/email/configuration-sets \ -H "Authorization: Bearer $SPLASHIFY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "production", "suppression_options": "BOUNCE_AND_COMPLAINT" }'

Save the config_set_id from the response.

2. Add a webhook destination

curl https://apis.splashifypro.com/api/v1/partner/email/configuration-sets/$CONFIG_SET_ID/event-destinations \ -H "Authorization: Bearer $SPLASHIFY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "production-webhook", "destination_type": "WEBHOOK", "webhook_url": "https://yourapp.com/webhooks/splashify", "webhook_secret": "your-shared-secret-32-chars", "matching_event_types": ["send", "delivered", "bounce", "complaint", "open", "click"] }'

Security: Store the webhook_secret somewhere your endpoint can read it (env var). The API will never echo it back — to rotate, PATCH a new value.

3. Reference the config set on send

curl https://apis.splashifypro.com/api/v1/partner/email/send \ -H "Authorization: Bearer $SPLASHIFY_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "hello@yourcompany.com", "to": ["customer@example.com"], "subject": "Welcome", "html_body": "<h1>Hi</h1>", "configuration_set_name": "production" }'

Within seconds your endpoint receives a Send event, then Delivery, etc.

Payload shape

We follow the AWS SES event-publishing JSON envelope. Code written against AWS SES SNS subscriptions consumes our webhooks by swapping the auth header verification.

{ "eventType": "Delivery", "mail": { "timestamp": "2026-05-03T12:34:56Z", "messageId": "550e8400-e29b-41d4-a716-446655440000", "source": "hello@yourcompany.com", "destination": ["customer@example.com"] }, "delivery": { "timestamp": "2026-05-03T12:34:57Z", "recipients": ["customer@example.com"], "smtpResponse": "250 OK" } }

Every event has the top-level eventType and mail fields. The event-specific payload is nested under a key matching the lowercase event type — delivery, bounce, complaint, etc.

Headers

Every POST carries:

HeaderPurpose
Content-Typeapplication/json
User-AgentSplashify-Pro-Webhook/1.0
X-Splashify-EventEvent type — Send, Delivery, Bounce, …
X-Splashify-Signaturesha256=<hex> HMAC-SHA256 of the raw body keyed by your webhook_secret
X-Splashify-TimestampUnix seconds — protects against replay
X-Splashify-Delivery-IDUUID per delivery attempt — use for idempotency

Quick verify in Node

import crypto from "crypto"; app.post("/webhooks/splashify", express.raw({ type: "application/json" }), (req, res) => { const signature = req.header("x-splashify-signature") || ""; const expected = "sha256=" + crypto .createHmac("sha256", process.env.SPLASHIFY_WEBHOOK_SECRET) .update(req.body) .digest("hex"); if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { return res.status(401).end(); } const event = JSON.parse(req.body.toString()); // process event... res.status(200).end(); });

Next