Pluma
Docs index
docs/guides/deploy-webhook.md View markdown →

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 or localhost.
  • 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.