Webhooks

Receive real-time notifications when events happen in your ConsentProof account.

Overview

Webhooks allow you to receive HTTP POST requests to your server whenever specific events occur. This enables you to:

  • Sync consent data with your CRM or database
  • Trigger workflows when users grant or withdraw consent
  • Update your application in real-time
  • Build audit logs and compliance reports

Creating a Webhook

Create a webhook via the API or dashboard:

Create webhookbash
curl -X POST https://api.consentproof.io/v1/webhooks \
  -H "X-API-Key: your_api_key" \
  -H "X-API-Secret: your_api_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-app.com/webhooks/consentproof",
    "events": ["consent.created", "consent.withdrawn"]
  }'

Note: The secret field is optional. If not provided, a secure secret will be auto-generated (prefixed with whsec_).

Response:

Responsejson
{
  "success": true,
  "data": {
    "id": "whk_abc123",
    "url": "https://your-app.com/webhooks/consentproof",
    "events": ["consent.created", "consent.withdrawn"],
    "secret": "whsec_a1b2c3d4e5f6...",
    "is_active": true,
    "created_at": "2024-01-15T10:30:00Z"
  },
  "meta": {
    "message": "Save the webhook secret now - it will not be shown again."
  }
}

Important

The webhook secret is only returned once when the webhook is created. Save it securely - you'll need it to verify webhook signatures.

Available Events

Subscribe to any of these events:

EventDescription
consent.createdA new consent record was created
consent.updatedA consent record was updated
consent.withdrawnConsent was withdrawn
consent.batch_createdMultiple consents were created in batch
policy.createdA new policy version was created
policy.updatedA policy was updated
policy.deletedA policy was deleted

Use * to subscribe to all events.

Webhook Payload

Each webhook delivery includes a JSON payload with the event details:

consent.created payloadjson
{
  "id": "evt_xyz789",
  "type": "consent.created",
  "created_at": "2024-01-15T10:35:00Z",
  "data": {
    "id": "con_abc123",
    "subject_id": "user_123",
    "subject_email": "user@example.com",
    "policy_id": "pol_def456",
    "consent_type": "marketing",
    "granted": true,
    "consent_hash": "sha256:a1b2c3d4e5f6...",
    "metadata": {
      "ip_address": "192.168.1.1",
      "source": "signup_form"
    },
    "recorded_at": "2024-01-15T10:35:00Z"
  }
}

Verifying Signatures

Every webhook includes an HMAC-SHA256 signature in the X-Signature header. Always verify this signature to ensure the webhook is from ConsentProof.

Headers Included

HeaderDescription
X-SignatureHMAC-SHA256 signature of the payload
X-TimestampUnix timestamp of when the webhook was sent
X-Webhook-IDUnique identifier for this webhook configuration

Verification Example

verify-webhook.jsjavascript
import crypto from 'crypto';

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// Express.js example
app.post('/webhooks/consentproof', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-signature'];
  const payload = req.body.toString();

  if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const event = JSON.parse(payload);

  // Handle the event
  switch (event.type) {
    case 'consent.created':
      handleConsentCreated(event.data);
      break;
    case 'consent.withdrawn':
      handleConsentWithdrawn(event.data);
      break;
    default:
      console.log('Unhandled event type:', event.type);
  }

  res.json({ received: true });
});

Security Warning

Always verify webhook signatures before processing. Never trust webhooks without verification.

Retry Policy

If your endpoint doesn't respond with a 2xx status code, we'll retry the webhook:

  • Attempt 1: Immediately
  • Attempt 2: After 1 minute
  • Attempt 3: After 5 minutes
  • Attempt 4: After 30 minutes
  • Attempt 5: After 2 hours

After 5 failed attempts, the webhook is marked as failed. You can view delivery history in your dashboard.

Best Practices

  • Respond quickly

    Return a 200 response immediately, then process the event asynchronously

  • Handle duplicates

    Use the event ID to deduplicate in case of retries

  • Use HTTPS

    Webhook URLs must use HTTPS for security

  • Test with the dashboard

    Use the "Send Test" feature to test your endpoint

Related Documentation