Webhooks let your destination site revalidate the second a post goes live, instead of waiting for the next ISR / SWR cycle.
Webhooks are optional. Without them, your destination still picks up new posts on its next revalidation interval (default 5 minutes).
When Mentionwell fires
| Event | Path Mentionwell POSTs to your destination |
|---|---|
| Post published | POST {destinationBaseUrl}{revalidateEndpoint} |
| Post updated | same |
| Post deleted | same (with { deleted: true }) |
The path is configurable in Settings → Delivery → Revalidate Endpoint. Default: /api/mentionwell-revalidate.
Payload
{
"event": "post.published",
"siteSlug": "your-site-slug",
"post": {
"slug": "five-questions-to-ask-before-you-buy",
"title": "Five Questions to Ask Before You Buy",
"publishedAt": "2026-04-21T15:00:00.000Z"
}
}
event is one of post.published, post.updated, or post.deleted. For deletions, post.publishedAt is the timestamp of the original publish. Always parse the body as raw text first (you need the exact bytes for signature verification), then JSON.parse it.
Signature
Every request includes a signature header:
X-Mentionwell-Signature: <hex hmac-sha256(rawBody, MENTIONWELL_WEBHOOK_SECRET)>
Verify it before trusting the payload.
Node.js
import crypto from "node:crypto";
export async function POST(req: Request) {
const raw = await req.text();
const sig = req.headers.get("x-mentionwell-signature");
const expected = crypto
.createHmac("sha256", process.env.MENTIONWELL_WEBHOOK_SECRET!)
.update(raw)
.digest("hex");
if (sig !== expected) return new Response("invalid signature", { status: 401 });
const { event, siteSlug, post } = JSON.parse(raw);
// post.slug, post.title, post.publishedAt
// event ∈ { "post.published", "post.updated", "post.deleted" }
// … revalidate /blog and /blog/<post.slug>
}
Python
import hmac, hashlib
def verify(raw_body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)
Delivery & retries
Webhook delivery happens once at publish time. A delivery is considered successful if your endpoint returns a 2xx response within ~10 seconds.
If it fails (non-2xx, network error, or timeout), the post still publishes inside Mentionwell and remains live on the reader API — only the webhook fan-out is missed. The post's deliveryStatus flips to failed and the last error message is stored on the post; the dashboard surfaces these in the Articles list with a "Push failed" badge.
To retry a failed delivery: re-publish the post from the dashboard (Unpublish → Republish). Future versions will add automatic retries with backoff — track via the deliveryStatus field if you need to backfill manually.
If your endpoint is reliably down for > 10 seconds, prefer pull mode: your destination polls the reader API on its own ISR/SWR cycle and can never miss a publish.
Where to find the secret
Open Ship → Webhook. The secret looks like whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.
The webhook secret is different from the API key. The API key authorises reading posts; the webhook secret authenticates outbound pushes from Mentionwell.