Generic webhook deploy
For any other host or CI: Cloudflare Pages, GitHub Actions, your own server, a Slack channel. Pluma sends a POST with JSON when something happens, signed so you can verify it comes from Pluma.
What it sends
POST /your-endpoint
Content-Type: application/json
User-Agent: Pluma-Webhooks/1
X-Pluma-Event: publish
X-Pluma-Delivery: 42
X-Pluma-Signature: sha256=5d1f…
{
"space": "acton-estero",
"events": [
{ "type": "entry.published", "entry_id": "12", "content_type": "event", "at": "2026-09-28T12:00:00Z" }
],
"triggered_at": "2026-09-28T12:00:30Z",
"test": false
}
events holds everything that happened in the batch (see debounce below).
Events
| Event | When |
|---|---|
entry.published |
An entry was published |
entry.unpublished |
A published entry was unpublished or archived |
content_type.changed |
A content type or its fields were created or changed |
Each webhook chooses which ones it listens to. By default, all three.
Verify the signature
X-Pluma-Signature is sha256= + the HMAC-SHA256 of the body exactly as it arrived, using the webhook's secret. The secret is shown only once, when you create the webhook.
import crypto from "node:crypto";
const expected = "sha256=" + crypto.createHmac("sha256", process.env.PLUMA_WEBHOOK_SECRET).update(rawBody).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers["x-pluma-signature"]));
Rules
- The URL must be
https://and point to the public internet: Pluma doesn't call private addresses orlocalhost. - 30-second debounce: a batch of publishes goes out in a single ping.
- Retries: up to 5 attempts if the response isn't 2xx or doesn't arrive within 10 seconds, waiting longer each time.
- Every attempt is logged in Deploy, with the response code and how long it took.