Less boo. More booked. Halloween offer: 30 days free on any paid plan. Claim 30 days freeEvery new account gets one free mailbox for warmup and replies. No domain to buy. See how it works

Skip to content

Delivery & retries

API referenceWebhooks

From the Webhooks API reference. Requests use the base URL https://app.warmerly.com/api/v1 and an API key, see Authentication.

Deliveries are dispatched by a background sweep (not real-time) that polls for new events every 5 minutes. Each delivery is a POST to your targetUrl, with content-type: application/json and the X-Warmerly-Signature header:

json
{
  "id": "9d1e0b7a-5e7b-4f10-b2aa-1c8f0d3e6a4b",
  "type": "score_drop",
  "accountId": "3a6f9e2e-4b7a-4e9a-9b1d-6e3a2f8c1a10",
  "occurredAt": "2026-08-18T09:00:00.000Z",
  "data": { "severity": "warning", "title": "Health score dropped", "body": "...", "scoreBefore": 88, "scoreAfter": 61 }
}

id is the ID of the underlying event and occurredAt is when it was recorded. data's shape varies by type. For score_drop, score_floor, oauth_disconnected, auth_fail and dns_changed it is { severity, title, body, scoreBefore, scoreAfter } (severity is info, warning or critical; the score fields can be null). For the other event types it is the stored event payload as-is, which is not separately documented per type (see Known gaps).

  • Each delivery is tried up to 3 times (0.5 s, then 1 s, between attempts). An attempt fails if your endpoint doesn't respond 2xx within 5 seconds, or errors.
  • Events are delivered in order. An event that fails all 3 attempts is not redelivered in a later sweep: the subscription moves on past it.
  • A subscription is automatically disabled (active: false) after 10 consecutive sweeps in which a delivery failed. Re-enable it with PATCH .../{id}.
  • Up to 50 events per subscription are delivered per sweep; if you have a burst larger than that, the remainder is delivered on the next sweep.
  • Redirects are never followed; a 3xx response counts as a failure, so respond 2xx directly from targetUrl.
  • lastDeliveryStatus is success or failed. On failure lastDeliveryError is one of http_<status>, timeout, connection_failed, unsafe_target_url or dns_resolution_failed.
API reference

#Verifying deliveries

Every delivery carries an X-Warmerly-Signature header: the hex-encoded HMAC-SHA256 of the raw request body, signed with your subscription's secret.

text
X-Warmerly-Signature: 3f9a7c2e...  (hex-encoded HMAC-SHA256 of the raw body)

Verify it by recomputing the HMAC over the exact bytes of the received body and comparing:

js
const crypto = require("crypto");
const expected = crypto.createHmac("sha256", subscriptionSecret).update(rawBody).digest("hex");
const valid = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(receivedSignature));
Was this page helpful?