Guide to Attentive Webhooks: Features and Best Practices
Attentive webhooks notify your systems about SMS and email subscriber activity: someone subscribes, a message is sent, an email is opened. If you're syncing subscriber state to a CRM, triggering downstream automation, or building analytics off Attentive activity, webhooks are how you react without polling.
This guide covers how Attentive webhooks work, the events you can subscribe to, how to verify the x-attentive-hmac-sha256 signature, the delivery behavior, and the best practices for running them in production.
What are Attentive webhooks?
Attentive webhooks are HTTP POSTs sent to an endpoint you configure, each carrying a JSON payload about a subscriber event. Payloads include a type, a timestamp (Unix milliseconds), and company and subscriber objects. You subscribe to the event types you care about, and Attentive signs each delivery so you can confirm it came from Attentive.
The signature scheme is a plain HMAC in the x-attentive-hmac-sha256 header with no timestamp, so there's no built-in replay protection; that's yours to add.
Attentive webhook features
| Feature | Details |
|---|---|
| Configuration | Dashboard (custom app > Webhooks, "Universal") or Webhooks API (POST /webhooks) |
| Signature header | x-attentive-hmac-sha256 |
| Signature scheme | hex HMAC-SHA256 of the raw body, keyed with the per-webhook signing key |
| Replay protection | None; no timestamp in the signature |
| Payload | type, timestamp (Unix ms), company, subscriber |
| Retries | Exponential backoff for up to 3 days on non-2xx |
| Auto-disable | Endpoints failing for multiple consecutive days |
| Ordering | Not guaranteed |
| Delivery timeout | Undocumented |
| SDK | No official server-side SDK |
Common events
Attentive groups events by channel. SMS and email subscriber events are the common ones:
| Event | Fires when |
|---|---|
sms.subscribed | A subscriber opts in to SMS |
sms.sent | An SMS is sent to a subscriber |
email.opened | A subscriber opens an email |
email.sent | An email is sent to a subscriber |
email.unsubscribed | A subscriber opts out of email |
Subscribe only to the events you process, and consult Attentive's webhook reference for the full list.
Setting up Attentive webhooks
Configure webhooks in the Attentive dashboard (your custom app's Webhooks tab, "Universal" type), or via the Webhooks API using the "Subscription" type:
curl -X POST "https://api.attentivemobile.com/v1/webhooks" \
-H "Authorization: Bearer $ATTENTIVE_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-app.example.com/webhook", "subscriptions": ["sms.subscribed", "email.opened"] }'
Attentive shows the per-webhook signing key (a "client secret") in the webhook settings; copy it into your environment.
Securing Attentive webhooks
Each delivery carries an x-attentive-hmac-sha256 header: a hex-encoded HMAC-SHA256 of the raw request body, keyed with your per-webhook signing key. Recompute it over the exact bytes and compare in constant time.
const crypto = require("crypto");
const SIGNING_KEY = process.env.ATTENTIVE_SIGNING_KEY;
function verify(rawBody, signature) {
const expected = crypto.createHmac("sha256", SIGNING_KEY).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signature || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
if (!verify(req.body, req.headers["x-attentive-hmac-sha256"])) {
return res.sendStatus(401);
}
res.sendStatus(200); // acknowledge fast
processQueue.add(JSON.parse(req.body)); // process asynchronously
});
The same check in Python (matching Attentive's own example, which uses hmac.compare_digest):
import hashlib
import hmac
import os
SIGNING_KEY = os.environ["ATTENTIVE_SIGNING_KEY"].encode()
def verify(raw_body: bytes, signature: str) -> bool:
expected = hmac.new(SIGNING_KEY, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or "")
Attentive webhook limitations and pain points
No timestamp, so no replay protection
The Problem: The signature covers the body only. A captured, validly signed payload can be replayed later and it will still verify, so signature verification alone doesn't prove a request is fresh.
Why It Happens: Attentive's scheme is a plain body HMAC without a signed timestamp.
Workarounds:
- Make processing idempotent so a replayed payload has no additional effect.
- Dedupe on identifiers in the payload rather than trusting each POST as unique.
- Use the payload's
timestampto reject implausibly old deliveries if you need a freshness check.
How Hookdeck Can Help: Hookdeck deduplicates deliveries at the edge, filtering replays and retries before they reach your app. See our guide to webhook idempotency.
Ordering is not guaranteed
The Problem: Events can arrive out of order. A state machine that assumes, say, sms.subscribed always precedes sms.sent will get into impossible states.
Why It Happens: Parallel delivery doesn't preserve per-subscriber ordering.
Workarounds:
- Sort by the payload
timestamprather than trusting receipt order. - Treat each event as a trigger to re-check current state, not as the authoritative sequence.
How Hookdeck Can Help: Hookdeck's queueing and replay let you re-process events in a controlled order during recovery. See our guide to webhook ordering.
Auto-disable after sustained failures
The Problem: Attentive retries non-2xx deliveries with exponential backoff for up to 3 days, and endpoints that fail for multiple consecutive days are auto-disabled. Once disabled, you receive nothing until you re-enable.
Why It Happens: Attentive stops delivering to endpoints that look persistently broken.
Workarounds:
- Acknowledge with a 2xx fast so transient downstream issues don't accumulate as failures.
- Monitor webhook status and re-enable promptly after fixing an outage.
How Hookdeck Can Help: Hookdeck always accepts deliveries from Attentive and absorbs downstream failures itself, keeping your webhook active while it retries to your service on a schedule you control.
Undocumented delivery timeout
The Problem: Attentive doesn't document a specific response timeout, so you can't rely on a known budget for synchronous work in your handler.
Why It Happens: The timeout simply isn't published.
Workarounds:
- Acknowledge as fast as possible and process asynchronously; assume the budget is small.
- Do no blocking work before responding.
How Hookdeck Can Help: Hookdeck acknowledges Attentive within milliseconds and forwards to your endpoint on a timeout you control, so an unknown upstream budget stops being a risk.
Best practices
Verify with the per-webhook signing key
Compute hex HMAC-SHA256 over the raw body with the signing key and compare in constant time using crypto.timingSafeEqual / hmac.compare_digest.
Add your own replay protection
Since there's no signed timestamp, dedupe on payload identifiers and use the timestamp field to reject stale deliveries if you need freshness.
Acknowledge fast, process asynchronously
Return 2xx immediately and defer work to a queue, especially given the undocumented timeout. See why to process webhooks asynchronously.
Don't assume ordering
Sort by the payload timestamp and design handlers to tolerate out-of-order events.
Monitor for auto-disable
Watch webhook status and re-enable quickly after any sustained failure so you don't silently miss events.
Make Attentive webhooks production-ready
Hookdeck verifies x-attentive-hmac-sha256, deduplicates, and durably queues every subscriber event
Conclusion
Attentive webhooks give you SMS and email subscriber activity in real time, verified with a straightforward x-attentive-hmac-sha256 HMAC over the raw body. The things to plan around are what the scheme leaves out: no timestamp means no replay protection, ordering isn't guaranteed, the delivery timeout is undocumented, and sustained failures auto-disable the webhook.
That puts replay protection, idempotency, ordering tolerance, fast acknowledgement, and status monitoring on you. Hookdeck verifies the signature, deduplicates, and durably queues every event at the edge, so your systems process verified, unique subscriber events and a bad day downstream never disables your Attentive webhook.
Get started with Hookdeck for free and handle Attentive webhooks reliably in minutes.