All documentation
Authentication

Webhooks: Verify Signatures in Node.js and Python

Verify PulseGrid webhooks with the official SDK 0.2.0 helpers using the untouched raw request body.

Multi-language

Overview

Every production webhook receiver should verify the PulseGrid signature before processing the JSON. SDK 0.2.0 includes verification helpers in both official SDKs, so application code does not need to reimplement HMAC logic for every framework. Critical rule: verify the original raw request body. Parsing JSON and serializing it again can change whitespace/key order and invalidate a correct signature.

Setup

Node.js / Express: 1. Store PULSEGRID_WEBHOOK_SECRET on the server. 2. Configure the webhook route with express.raw({ type: 'application/json' }). 3. Pass req.headers and req.body to constructWebhookEvent. 4. Process event.payload only after verification succeeds. Python / Django: 1. Store PULSEGRID_WEBHOOK_SECRET on the server. 2. Pass request.headers and request.body to construct_webhook_event. 3. CSRF-exempt the external webhook route when appropriate. 4. Process event['payload'] only after verification succeeds. The helpers reject invalid/expired signatures using the timestamp tolerance.

Code example

Webhooks: Verify Signatures in Node.js and Python
Node.js / Express
import express from "express";
import { constructWebhookEvent } from "pulsegrid/webhooks";

const app = express();

app.post(
  "/webhooks/pulsegrid",
  express.raw({ type: "application/json" }),
  async (req, res) => {
    try {
      const event = constructWebhookEvent({
        secret: process.env.PULSEGRID_WEBHOOK_SECRET,
        headers: req.headers,
        body: req.body,
      });

      await processPulseGridEvent(event.payload);
      return res.status(200).json({ received: true });
    } catch (error) {
      return res.status(401).json({ error: error.code || "invalid_webhook" });
    }
  }
);

Notes

Do not log or return the signing secret. Rotate it if exposed. If you use another language without an official SDK, implement the documented timestamp + '.' + raw body HMAC-SHA256 algorithm with constant-time comparison and replay-age validation.