Skip to content

Quickstart: Webhooks for Developers

This guide walks developers through setting up webhook integration with WhiteLabelCRO.

Prerequisites

Before you begin: - Basic understanding of HTTP webhooks and HMAC signatures - Publicly accessible HTTPS endpoint (or ngrok for testing) - Admin access to WhiteLabelCRO CRM - HTTP client or tool (curl, Postman, or code)

Webhooks vs Integration API Actions (Important)

Webhooks are outbound only - they deliver events from WhiteLabelCRO to your external system.

To create or update data in WhiteLabelCRO (e.g., create leads, add notes, update client status), use Integration API actions. These are standard HTTP POST/PATCH requests authenticated with an API key.

Integration API actions can be called from: - Zapier (using WhiteLabelCRO actions) - n8n (using HTTP Request nodes) - Make (using HTTP modules) - Custom code or internal systems (direct API calls)

This guide covers receiving events via webhooks only. For writing data into WhiteLabelCRO, see: - Integration Capabilities Overview - Zapier Actions, n8n Actions, or Make Actions

Step 1: Create Your Endpoint

Your webhook endpoint must: - Accept HTTP POST requests - Return 2xx status code (200-299) for successful receipt - Respond within 10 seconds - Handle duplicate deliveries (use event ID for deduplication)

Minimum viable endpoint:

POST https://your-domain.com/webhooks/wlcro

Responds with 200 OK and logs the request body.

Step 2: Obtain API Credentials

Get API Key

  1. Log in to WhiteLabelCRO CRM
  2. Navigate to Settings > Integrations > API Keys
  3. Click Create New Key
  4. Name it "Webhook Integration"
  5. Select scope: webhooks:write
  6. Copy the API key

Note Your Webhook URL

Your webhook URL must: - Use HTTPS (HTTP only allowed in development) - Be publicly accessible - Respond to POST requests

For local testing, use ngrok:

ngrok http 3000

Copy the HTTPS URL (e.g., https://abc123.ngrok.io/webhooks/wlcro).

Step 3: Register Your Webhook Subscription

Use curl or Postman to create a subscription:

curl -X POST https://your-api-url.com/api/v1/webhooks/subscriptions \
  -H "X-Api-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-domain.com/webhooks/wlcro",
    "eventTypes": ["client.created", "payment.succeeded"],
    "enabled": true
  }'

Response:

{
  "id": 123,
  "url": "https://your-domain.com/webhooks/wlcro",
  "eventTypes": ["client.created", "payment.succeeded"],
  "signingSecret": "abc123...",
  "enabled": true
}

Save the signingSecret - you'll need it for signature verification. It's only shown once.

See Webhooks API documentation for complete details.

Step 4: Implement Signature Verification

Every webhook delivery includes: - X-Webhook-Timestamp header (Unix epoch seconds) - X-Webhook-Signature header (sha256=<hex>)

Verification steps:

  1. Extract both headers
  2. Compute HMAC-SHA256 of "{timestamp}.{raw_body}" using signing secret
  3. Convert to lowercase hex and prepend sha256=
  4. Compare with received signature (constant-time comparison)
  5. Optionally reject old timestamps (> 5 minutes)

Example (pseudocode):

timestamp = request.headers['X-Webhook-Timestamp']
signature = request.headers['X-Webhook-Signature']
payload = timestamp + '.' + raw_request_body

computed = 'sha256=' + hmac_sha256(signing_secret, payload).hex().lower()

if !constant_time_equals(computed, signature):
    return 401 Unauthorized

See Webhook Security documentation for code examples.

Step 5: Handle Webhook Delivery

Your endpoint should:

1. Verify the signature (Step 4)

2. Parse the JSON body:

{
  "id": 12345,
  "type": "client.created",
  "createdUtc": "2026-01-28T10:30:00Z",
  "payload": {
    "client_id": 5678,
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com"
  }
}

3. Check for duplicates (use id field)

4. Process the event (business logic)

5. Return 200 OK immediately

Don't perform long-running operations before returning. Use queues/background jobs for async processing.

Step 6: Test Your Integration

Send a Test Delivery

Using the subscription ID from Step 3:

curl -X POST https://your-api-url.com/api/v1/webhooks/subscriptions/123/test \
  -H "X-Api-Key: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "eventType": "client.created",
    "useSamplePayload": true
  }'

Response:

{
  "success": true,
  "statusCode": 200,
  "elapsedMs": 145,
  "responseBody": "OK"
}

Success criteria: - Your endpoint receives the POST request - Signature verification passes - Your endpoint returns 200 - Event is logged/processed

Trigger a Real Event

Create a test client in WhiteLabelCRO:

  1. Navigate to Clients > Add New Client
  2. Fill in details and save
  3. Within seconds, your webhook should receive client.created event

Check your logs to verify delivery.

Minimal Code Examples

Node.js Express

const express = require('express');
const crypto = require('crypto');

app.post('/webhooks/wlcro', express.raw({ type: 'application/json' }), (req, res) => {
  const timestamp = req.headers['x-webhook-timestamp'];
  const signature = req.headers['x-webhook-signature'];
  const payload = `${timestamp}.${req.body}`;

  const computed = 'sha256=' + crypto
    .createHmac('sha256', signingSecret)
    .update(payload)
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(signature))) {
    return res.status(401).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  console.log('Event received:', event.type, event.id);

  // Process event here

  res.status(200).send('OK');
});

Python Flask

import hmac
import hashlib
from flask import Flask, request

@app.route('/webhooks/wlcro', methods=['POST'])
def webhook():
    timestamp = request.headers.get('X-Webhook-Timestamp')
    signature = request.headers.get('X-Webhook-Signature')
    payload = f"{timestamp}.{request.data.decode()}"

    computed = 'sha256=' + hmac.new(
        signing_secret.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()

    if not hmac.compare_digest(computed, signature):
        return 'Invalid signature', 401

    event = request.json
    print(f"Event received: {event['type']} {event['id']}")

    # Process event here

    return 'OK', 200

Error Handling

Retry Behavior

If your endpoint fails: - Returns non-2xx status - Times out (> 10 seconds) - Connection error

WhiteLabelCRO will retry up to 10 times with exponential backoff.

Circuit Breaker

After 20 consecutive failures, the subscription auto-disables. Re-enable after fixing the issue.

Duplicate Deliveries

Due to retries, the same event may arrive multiple times. Always check event id for deduplication:

if (processedEventIds.has(event.id)) {
  return res.status(200).send('Already processed');
}
processedEventIds.add(event.id);

Going to Production

Security Checklist

  • ✅ Always verify signatures
  • ✅ Use HTTPS (not HTTP)
  • ✅ Validate timestamp (reject old requests)
  • ✅ Don't expose signing secret in logs
  • ✅ Use constant-time comparison for signatures

Performance Checklist

  • ✅ Respond within 10 seconds
  • ✅ Use async processing for long operations
  • ✅ Implement deduplication
  • ✅ Log deliveries for debugging
  • ✅ Monitor failure rates

Monitoring

Track: - Webhook delivery success rate - Processing time - Duplicate event count - Signature verification failures

Troubleshooting

Signature Verification Fails

  • Using correct signing secret from subscription creation?
  • Computing HMAC over "{timestamp}.{raw_body}" (exact format)?
  • Using raw request body (before parsing JSON)?
  • Using constant-time comparison?

Webhooks Not Arriving

  • Subscription is enabled?
  • URL is publicly accessible?
  • Firewall allows WhiteLabelCRO IPs?
  • Check delivery logs in WhiteLabelCRO Admin Portal

Timeouts

  • Endpoint responds within 10 seconds?
  • Move long operations to background queue
  • Return 200 immediately after validation

Next Steps

Add More Event Types

Edit your subscription to include: - payment.failed - Alert on declined payments - invoice.created - Sync with accounting - agreement.signed - Trigger post-signature workflows

Implement Business Logic

  • Update external CRM
  • Send notifications
  • Trigger workflows
  • Sync to data warehouse

Learn More