DPDPEnforced May 13, 2027Checklist →
++

Webhooks & API

Sync consent grants, withdrawals and rights requests to your CRM, CDP or data warehouse with signed ConsentPlix webhooks. Includes a Node.js receiver.

Updated October 12, 2026

ConsentPlix sends a webhook every time consent changes or a rights request moves forward. Use them to keep your CRM, customer data platform or warehouse in line with what each person has agreed to.

Events

EventSent whenWhat you usually do
consent.grantedA person opts in to one or more purposesTurn on analytics or marketing for that person
consent.withdrawnA person withdraws consent they gave earlierStop marketing emails, remove ad audiences, clear tracking cookies
rights.submittedA new rights request is filedAlert your DPO or open a ticket
rights.resolvedA rights request is closedConfirm completion to the person

Verify the signature

Every webhook includes an x-consentplix-signature header. It is an HMAC-SHA256 of the raw request body, using your webhook secret. Always check it before trusting the payload.

Node.js and Express example

import express from "express";
import { createHmac, timingSafeEqual } from "node:crypto";

const app = express();
const WEBHOOK_SECRET = process.env.CONSENTPLIX_WEBHOOK_SECRET!;

// Keep the raw body: the signature is computed over the exact bytes sent.
app.post(
  "/api/webhooks/consentplix",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.header("x-consentplix-signature");
    if (!signature) return res.status(400).send("Missing signature");

    const expected = createHmac("sha256", WEBHOOK_SECRET).update(req.body).digest("hex");
    const a = Buffer.from(signature, "utf8");
    const b = Buffer.from(expected, "utf8");

    // timingSafeEqual throws if lengths differ, so check length first.
    if (a.length !== b.length || !timingSafeEqual(a, b)) {
      return res.status(401).send("Invalid signature");
    }

    const event = JSON.parse(req.body.toString("utf8"));

    if (event.event === "consent.withdrawn") {
      // e.g. await crm.suppressMarketing(event.data.subject_key);
    }

    return res.status(200).json({ received: true });
  },
);

Return a 2xx status quickly and do slow work in a background job. Failed deliveries are retried with exponential backoff.

Common destinations

  • CRMs such as Salesforce or HubSpot: update a consent field on the contact.
  • CDPs such as Segment: send a track or identify call with the new consent state.
  • Warehouses such as Snowflake or S3: append each event for reporting.