Home/Blog/Salesforce Webhooks: Complete Guide with Data Cloud Setup [2025]
Technology

Salesforce Webhooks: Complete Guide with Data Cloud Setup [2025]

Complete guide to Salesforce webhooks including Data Cloud setup, payload examples.

By InventiveHQ Team
Salesforce Webhooks: Complete Guide with Data Cloud Setup [2025]

When a customer record is updated in Salesforce, a deal closes, or data synchronizes between systems, you need to know immediately—not when your polling script runs in 5 minutes. Salesforce webhooks solve this problem by sending real-time HTTP POST notifications to your server the moment events occur, enabling you to:

  • Track record changes instantly when accounts, contacts, or custom objects are created, updated, or deleted
  • Synchronize data across systems in real-time using Change Data Capture (CDC) events
  • Trigger workflows automatically when business-critical data changes in Salesforce
  • Monitor data quality by tracking validation errors and data sync status
  • Build integrations that react to Salesforce events without constant API polling

Salesforce webhooks use industry-standard HMAC-SHA256 signature verification to ensure every notification authentically comes from your Salesforce organization, protecting your application from spoofed requests. In this comprehensive guide, you'll learn how to set up Salesforce webhooks, implement secure signature verification in Node.js, Python, and PHP, handle Change Data Capture events, and build production-ready webhook endpoints.

Testing your webhook integration is crucial before going live. Our Webhook Payload Generator tool lets you create properly signed Salesforce webhook payloads with custom event data, allowing you to test your signature verification logic and event handlers without configuring Data Cloud or exposing your local development environment.

What Are Salesforce Webhooks?

Salesforce webhooks are HTTP POST callbacks that Salesforce sends to your specified endpoint URL whenever events occur in your Salesforce organization. Unlike traditional API polling where your application repeatedly queries Salesforce's servers asking "did anything happen?", webhooks invert this model—Salesforce proactively notifies your server the instant a record changes, data syncs, or a platform event fires.

The webhook architecture follows this flow:

[Salesforce Event Occurs] → [Salesforce Server] → [HTTP POST to Your Endpoint] → [Your Application Logic]

Salesforce webhooks are delivered through multiple mechanisms:

  1. Change Data Capture (CDC): Real-time events for record changes (create, update, delete, undelete)
  2. Platform Events: Custom event-driven messaging within Salesforce
  3. Data Cloud Webhooks: Data synchronization and integration events from Data Cloud
  4. Streaming API: Push notifications using long-lived connections (CometD protocol)

Key differences from generic webhooks:

  1. Event Replay: Salesforce provides replay IDs allowing you to replay events from a specific point
  2. Transaction Context: Events include transaction keys and sequence numbers for ordering
  3. Change Metadata: Detailed information about which fields changed and their old/new values
  4. Multi-Entity Support: Subscribe to changes across multiple object types with single configuration
  5. Governor Limits Integration: Event delivery respects Salesforce API limits

Benefits specific to Salesforce webhooks:

  • Real-time synchronization between Salesforce and external systems without polling
  • Reduced API usage by eliminating constant queries for changes
  • Transaction-level change tracking with before/after field values
  • Automatic handling of record merges, undeletes, and cascade operations
  • Integration with Salesforce's security model (sharing rules, field-level security)

Prerequisites for setting up Salesforce webhooks:

  • Active Salesforce organization (Developer Edition or higher recommended)
  • Data Cloud or Platform Events enabled (varies by license type)
  • Publicly accessible HTTPS endpoint (localhost won't work without tunneling)
  • SSL/TLS certificate on your webhook endpoint (required for security)
  • Ability to handle HTTP POST requests with JSON payloads
  • (Recommended) API access to manage webhook configurations programmatically

Setting Up Salesforce Webhooks

Salesforce offers multiple webhook mechanisms. This guide focuses on Data Cloud webhooks, which provide the most flexible integration options for external systems.

Step 1: Access Data Cloud Settings

  1. Log in to your Salesforce organization
  2. Navigate to Setup (gear icon, top right)
  3. In Quick Find, search for Data Cloud
  4. Click Data Cloud Setup to access Data Cloud settings
  5. Ensure Data Cloud is enabled for your organization

Note: Data Cloud may require specific licenses. Check with your Salesforce administrator if you don't see this option.

Step 2: Generate Secret Key for Signature Validation

Salesforce uses HMAC-SHA256 signature verification to authenticate webhook requests.

  1. In Data Cloud Setup, navigate to API Access section
  2. Click Webhook Secret Keys
  3. Click Generate New Secret Key
  4. Copy the generated key immediately (shown only once)
  5. Store securely in your application's environment variables

Example secret key format:

sk_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6

Important: Each webhook endpoint should have its own unique secret key for security isolation.

Step 3: Configure Webhook Endpoint

  1. In Data Cloud Setup, go to Webhooks section
  2. Click New Webhook
  3. Enter configuration details:

Webhook Configuration Fields:

  • Name: Descriptive name (e.g., "Production Record Changes")
  • Endpoint URL: Your HTTPS URL (e.g., https://yourdomain.com/webhooks/salesforce)
  • Active: Toggle to enable/disable webhook
  • Secret Key: Select the secret key generated in Step 2

URL Requirements:

  • Must use HTTPS (HTTP not supported)
  • Must be publicly accessible
  • Should be a dedicated endpoint for Salesforce events
  • Path can be customized to your application structure

Step 4: Subscribe to Events

Configure which events trigger webhook deliveries:

Change Data Capture Events:

  1. Navigate to Setup > Change Data Capture

  2. Click Enable Change Data Capture

  3. Select objects to track:

    • ☐ Account - Customer and prospect accounts
    • ☐ Contact - Individual contacts
    • ☐ Opportunity - Sales opportunities
    • ☐ Lead - Potential customers
    • ☐ Case - Customer support cases
    • ☐ Custom Objects - Your organization's custom data
  4. Select change types:

    • ☐ Create - New records
    • ☐ Update - Modified records
    • ☐ Delete - Deleted records
    • ☐ Undelete - Restored records

Data Cloud Events:

  1. In Data Cloud Setup > Webhooks
  2. Configure event subscriptions:
    • ☐ Data Sync Completed - Synchronization finished
    • ☐ Data Quality Issues - Validation failures
    • ☐ Record Matching - Duplicate detection events

Step 5: Configure Retry Policy

Set up retry behavior for failed webhook deliveries:

  1. In webhook configuration, expand Advanced Settings
  2. Configure retry parameters:
    • Max Retries: 3-5 attempts recommended
    • Retry Interval: Exponential backoff (e.g., 1s, 2s, 4s, 8s)
    • Timeout: Request timeout (10-30 seconds)

Step 6: Test Your Integration

Salesforce provides testing capabilities:

  1. In webhook configuration, click Send Test Event
  2. Select event type (e.g., Account Create)
  3. Review sample payload format
  4. Send to your endpoint
  5. Verify your endpoint receives and processes the test

Verify in Your Application:

  • Check logs for incoming request
  • Confirm signature verification passes
  • Validate payload structure matches expectations

Step 7: Enable the Webhook

  1. Toggle Active to ON in webhook configuration
  2. Click Save to activate
  3. Events will now be sent to your endpoint in real-time

Monitoring Webhook Delivery

Track webhook health and delivery status:

  1. Navigate to Setup > Event Monitoring
  2. Filter by webhook events
  3. Review:
    • Delivery success rate
    • Failed delivery attempts
    • Response times from your endpoint
    • Error messages

Set up alerts for delivery failures exceeding threshold.

Pro Tips for Setup

Best Practices:

  • Use separate webhooks for sandbox/test and production environments
  • Configure different endpoints for different event types (CDC vs Data Cloud)
  • Enable all event types initially for debugging, then narrow down to needed events
  • Set up monitoring dashboards for webhook metrics
  • Document your secret key locations for team members
  • Implement log archiving for webhook delivery history

Common Mistakes to Avoid:

  • ❌ Using HTTP instead of HTTPS (will fail validation)
  • ❌ Sharing secret keys across multiple endpoints (security risk)
  • ❌ Not testing before enabling (broken endpoints cause event loss)
  • ❌ Subscribing to all objects when only needing a few (unnecessary processing)
  • ❌ Using localhost URLs without ngrok tunneling (Salesforce can't reach them)
  • ❌ Forgetting to configure retry policy (no automatic retry on failure)

Rate Limits and Restrictions:

  • No explicit rate limits on webhook deliveries (events sent as they occur)
  • Maximum endpoint URL length: 2000 characters
  • Maximum retry period: Configurable up to 24 hours
  • Event batch sizes vary (typically 1-10 events per POST for CDC)
  • API limits apply to webhook configuration changes

Salesforce Webhook Events & Payloads

Salesforce sends webhook payloads as JSON objects containing event metadata and change details. The exact structure varies by event source (Change Data Capture, Platform Events, Data Cloud).

Event Types Overview

Event TypeDescriptionCommon Use Case
record.createdNew record created in SalesforceTrack new accounts, contacts, leads for CRM integration
record.updatedExisting record modifiedSynchronize field changes to external databases
record.deletedRecord deleted from SalesforceRemove corresponding data from external systems
record.undeletedDeleted record restoredRestore previously removed data in external systems
data.syncData Cloud synchronization completedMonitor data pipeline status and quality
webhook.testTest event for endpoint verificationValidate webhook configuration and connectivity

Common Fields Across All Events

Every Salesforce webhook event includes these base fields:

  • event.type - Event type identifier (record.created, data.sync, etc.)
  • event.createdDate - ISO 8601 timestamp when event occurred
  • event.replayId - Unique replay identifier for event recovery
  • data.event.replayId - Duplicate replay ID in data section (for CDC compatibility)
  • data.payload - Event-specific payload with record/sync details

Detailed Event Examples

Event: record.created

Description: A new record was created in Salesforce (triggered by Change Data Capture).

Payload Structure:

{
  "event": {
    "type": "record.created",
    "createdDate": "2025-01-24T12:00:00.000Z",
    "replayId": 123456
  },
  "data": {
    "event": {
      "replayId": 123456
    },
    "payload": {
      "Id": "rec_abc123",
      "Name": "Acme Corporation",
      "Type": "Customer",
      "Industry": "Technology",
      "CreatedDate": "2025-01-24T12:00:00.000Z",
      "ChangeEventHeader": {
        "entityName": "Account",
        "changeType": "CREATE",
        "changeOrigin": "com/salesforce/api/rest/56.0",
        "transactionKey": "txn_def456",
        "sequenceNumber": 1,
        "commitTimestamp": 1643723456000
      }
    }
  }
}

Key Fields:

  • Id - Salesforce record ID (15 or 18 character)
  • ChangeEventHeader.entityName - Object type (Account, Contact, Opportunity, etc.)
  • ChangeEventHeader.changeType - CREATE, UPDATE, DELETE, UNDELETE
  • ChangeEventHeader.transactionKey - Groups related changes in same transaction
  • ChangeEventHeader.sequenceNumber - Order of changes within transaction
  • ChangeEventHeader.commitTimestamp - When transaction was committed

Event: record.updated

Description: An existing Salesforce record was modified.

Payload Structure:

{
  "event": {
    "type": "record.updated",
    "createdDate": "2025-01-24T13:30:00.000Z",
    "replayId": 123457
  },
  "data": {
    "event": {
      "replayId": 123457
    },
    "payload": {
      "Id": "rec_abc123",
      "Name": "Acme Corporation",
      "Type": "Customer",
      "Industry": "Healthcare",
      "LastModifiedDate": "2025-01-24T13:30:00.000Z",
      "ChangeEventHeader": {
        "entityName": "Account",
        "changeType": "UPDATE",
        "changeOrigin": "com/salesforce/api/rest/56.0",
        "transactionKey": "txn_ghi789",
        "sequenceNumber": 2,
        "commitTimestamp": 1643729400000,
        "changedFields": ["Industry"]
      }
    }
  }
}

Key Fields:

  • changedFields - Array of field API names that were modified
  • LastModifiedDate - When the record was last changed
  • All other fields show current values (not before/after deltas)

Important Note: Change Data Capture does NOT include old field values, only current state. For field-level audit trails, use Field History Tracking or store changes in your external system.

Event: record.deleted

Description: A record was deleted from Salesforce (moved to Recycle Bin).

Payload Structure:

{
  "event": {
    "type": "record.deleted",
    "createdDate": "2025-01-24T14:00:00.000Z",
    "replayId": 123458
  },
  "data": {
    "event": {
      "replayId": 123458
    },
    "payload": {
      "Id": "rec_abc123",
      "ChangeEventHeader": {
        "entityName": "Account",
        "changeType": "DELETE",
        "changeOrigin": "com/salesforce/api/rest/56.0",
        "transactionKey": "txn_jkl012",
        "sequenceNumber": 3,
        "commitTimestamp": 1643731200000
      }
    }
  }
}

Key Fields:

  • Only Id and ChangeEventHeader are present (record details are gone)
  • Use Id to remove corresponding data from external systems

Action Required: Archive or soft-delete the record in your external database. Don't permanently delete immediately in case of undelete event.

Event: data.sync

Description: Data Cloud completed a data synchronization operation.

Payload Structure:

{
  "event": {
    "type": "data.sync",
    "createdDate": "2025-01-24T15:00:00.000Z",
    "replayId": 123459
  },
  "data": {
    "event": {
      "replayId": 123459
    },
    "payload": {
      "syncId": "sync_xyz789",
      "entityName": "Contact",
      "recordCount": 150,
      "status": "completed",
      "startTime": "2025-01-24T14:45:00.000Z",
      "endTime": "2025-01-24T15:00:00.000Z"
    }
  }
}

Key Fields:

  • syncId - Unique identifier for this sync operation
  • entityName - Object type that was synchronized
  • recordCount - Number of records processed
  • status - completed, failed, or partial
  • startTime / endTime - Sync duration

Use Case: Monitor data pipeline health, track sync latency, alert on failures.

Event: webhook.test

Description: Test event sent when validating webhook configuration.

Payload Structure:

{
  "event": {
    "type": "webhook.test",
    "createdDate": "2025-01-24T16:00:00.000Z",
    "replayId": 123460
  },
  "data": {
    "event": {
      "replayId": 123460
    },
    "payload": {
      "message": "This is a test webhook event from Salesforce",
      "timestamp": "2025-01-24T16:00:00.000Z"
    }
  }
}

Use Case: Verify endpoint connectivity and signature verification before enabling production events.

Replay ID Usage

The replayId field enables event replay functionality:

// Store last processed replay ID
const lastReplayId = 123456;

// On application restart, request events after last processed ID
// Salesforce retains events for 24-72 hours (varies by configuration)

Replay Strategies:

  1. Store in Database: Persist replay ID after successful processing
  2. Use for Recovery: Replay missed events during downtime
  3. Idempotency Check: Skip already-processed events based on replay ID

Webhook Signature Verification

Why Signature Verification Matters

Without signature verification, attackers could:

  • Spoof webhook requests by sending fake events to your endpoint
  • Manipulate data by injecting false record changes or sync events
  • Trigger unintended actions like deleting valid records from external systems
  • Exploit business logic by fabricating data quality issues or sync completions

Salesforce's HMAC-SHA256 signature verification cryptographically proves that webhook requests genuinely originated from your Salesforce organization, preventing all these attack vectors.

Salesforce's Signature Method

Algorithm: HMAC-SHA256 (Hash-based Message Authentication Code with SHA-256)

Header Name: X-Salesforce-Signature

What's Signed: Salesforce creates a signature by:

  1. Taking the raw request body bytes (unmodified JSON)
  2. Computing HMAC-SHA256 hash using your secret key
  3. Encoding the signature as base64 or hex (based on configuration)
  4. Sending in X-Salesforce-Signature header

Additional Security:

  • Secret key uniquely tied to your Data Cloud instance
  • No timestamp header (use your own timestamp validation)
  • Separate keys per webhook endpoint for isolation

Step-by-Step Verification Process

  1. Extract the signature from X-Salesforce-Signature header
  2. Retrieve your secret key from environment variables
  3. Get the raw request body (must be unmodified bytes, not parsed JSON)
  4. Compute HMAC-SHA256 of raw body using secret key
  5. Encode signature as base64 or hex (match Salesforce configuration)
  6. Compare signatures using constant-time comparison (prevent timing attacks)
  7. Validate business logic (check replay ID hasn't been processed already)

Code Examples

Node.js / Express

const express = require('express');
const crypto = require('crypto');
const bodyParser = require('body-parser');

const app = express();

// IMPORTANT: Use raw body parser for webhook endpoint
app.use(
  '/webhooks/salesforce',
  bodyParser.raw({ type: 'application/json' })
);

// Signature verification function
function verifySignature(payload, signature, secret) {
  // Compute HMAC-SHA256 of raw payload
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(payload);
  const computedSignature = hmac.digest('base64'); // or 'hex' based on config

  // Constant-time comparison to prevent timing attacks
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(computedSignature)
  );
}

// Salesforce webhook endpoint
app.post('/webhooks/salesforce', async (req, res) => {
  try {
    // Extract signature from header
    const signature = req.get('X-Salesforce-Signature');
    if (!signature) {
      console.error('Missing X-Salesforce-Signature header');
      return res.status(401).json({ error: 'Missing signature' });
    }

    // Get raw body (Buffer)
    const payload = req.body;

    // Retrieve secret key from environment
    const secret = process.env.SALESFORCE_WEBHOOK_SECRET;
    if (!secret) {
      console.error('SALESFORCE_WEBHOOK_SECRET not configured');
      return res.status(500).json({ error: 'Server configuration error' });
    }

    // Verify signature
    const isValid = verifySignature(payload, signature, secret);
    if (!isValid) {
      console.error('Invalid Salesforce webhook signature');
      return res.status(403).json({ error: 'Invalid signature' });
    }

    // Parse payload after verification
    const event = JSON.parse(payload.toString());

    // Check for duplicate using replay ID
    const replayId = event.event.replayId;
    const alreadyProcessed = await checkReplayId(replayId);
    if (alreadyProcessed) {
      console.log(`Event ${replayId} already processed, skipping`);
      return res.status(200).json({ status: 'duplicate' });
    }

    // Process event
    console.log(`Processing Salesforce event: ${event.event.type}`);
    console.log(`Replay ID: ${replayId}`);

    // Return 200 immediately (process async if needed)
    res.status(200).json({ status: 'received' });

    // Async processing
    await processEventAsync(event);

  } catch (error) {
    console.error('Salesforce webhook processing error:', error);
    res.status(500).json({ error: 'Processing failed' });
  }
});

// Helper function to check replay ID
async function checkReplayId(replayId) {
  // Query your database for this replay ID
  // Return true if already processed
  return false; // Implement your logic
}

// Async event processing
async function processEventAsync(event) {
  const eventType = event.event.type;

  switch (eventType) {
    case 'record.created':
      await handleRecordCreated(event.data.payload);
      break;
    case 'record.updated':
      await handleRecordUpdated(event.data.payload);
      break;
    case 'record.deleted':
      await handleRecordDeleted(event.data.payload);
      break;
    case 'data.sync':
      await handleDataSync(event.data.payload);
      break;
    default:
      console.warn(`Unhandled event type: ${eventType}`);
  }
}

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Salesforce webhook server listening on port ${PORT}`);
});

Python / Flask

import hmac
import hashlib
import json
from flask import Flask, request, jsonify

app = Flask(__name__)

# Load secret key from environment
SECRET_KEY = 'your_secret_key_here'  # Use environment variable in production

def verify_signature(payload, signature, secret):
    """Verify HMAC-SHA256 signature"""
    # Compute HMAC-SHA256
    computed_hmac = hmac.new(
        secret.encode('utf-8'),
        payload,
        hashlib.sha256
    )
    computed_signature = computed_hmac.hexdigest()  # or .digest().encode('base64')

    # Constant-time comparison
    return hmac.compare_digest(signature, computed_signature)

@app.route('/webhooks/salesforce', methods=['POST'])
def salesforce_webhook():
    try:
        # Get signature from header
        signature = request.headers.get('X-Salesforce-Signature')
        if not signature:
            return jsonify({'error': 'Missing signature'}), 401

        # Get raw body (must be bytes)
        payload = request.get_data()

        # Verify signature
        is_valid = verify_signature(payload, signature, SECRET_KEY)
        if not is_valid:
            print('Invalid Salesforce webhook signature')
            return jsonify({'error': 'Invalid signature'}), 403

        # Parse payload after verification
        event = json.loads(payload)

        # Check for duplicate using replay ID
        replay_id = event['event']['replayId']
        if check_replay_id(replay_id):
            print(f'Event {replay_id} already processed')
            return jsonify({'status': 'duplicate'}), 200

        # Process event
        event_type = event['event']['type']
        print(f'Processing Salesforce event: {event_type}')
        print(f'Replay ID: {replay_id}')

        # Return 200 immediately
        return jsonify({'status': 'received'}), 200

    except Exception as error:
        print(f'Salesforce webhook processing error: {error}')
        return jsonify({'error': 'Processing failed'}), 500

def check_replay_id(replay_id):
    """Check if replay ID already processed"""
    # Implement database lookup
    return False

if __name__ == '__main__':
    app.run(port=3000, debug=False)

PHP

<?php
// Get secret key from environment
$secret = getenv('SALESFORCE_WEBHOOK_SECRET');
if (!$secret) {
    http_response_code(500);
    die(json_encode(['error' => 'Server configuration error']));
}

// Extract signature from header
$signature = $_SERVER['HTTP_X_SALESFORCE_SIGNATURE'] ?? '';
if (empty($signature)) {
    http_response_code(401);
    die(json_encode(['error' => 'Missing signature']));
}

// Get raw POST body
$payload = file_get_contents('php://input');

// Compute HMAC-SHA256
$computedSignature = hash_hmac('sha256', $payload, $secret);
// For base64: base64_encode(hash_hmac('sha256', $payload, $secret, true))

// Constant-time comparison
if (!hash_equals($signature, $computedSignature)) {
    error_log('Invalid Salesforce webhook signature');
    http_response_code(403);
    die(json_encode(['error' => 'Invalid signature']));
}

// Parse payload after verification
$event = json_decode($payload, true);
if (!$event) {
    http_response_code(400);
    die(json_encode(['error' => 'Invalid JSON']));
}

// Check for duplicate using replay ID
$replayId = $event['event']['replayId'] ?? null;
if ($replayId && checkReplayId($replayId)) {
    error_log("Event $replayId already processed");
    http_response_code(200);
    die(json_encode(['status' => 'duplicate']));
}

// Process event
$eventType = $event['event']['type'];
error_log("Processing Salesforce event: $eventType");
error_log("Replay ID: $replayId");

// Return 200 immediately
http_response_code(200);
echo json_encode(['status' => 'received']);

// Process async (implement your queue logic here)

function checkReplayId($replayId) {
    // Implement database lookup
    return false;
}
?>

Common Verification Errors

  • Parsing JSON before verification: Body modified, signature won't match
    • ✅ Use raw body parser, verify first, then parse JSON
  • Using wrong secret key: Test vs production keys are different
    • ✅ Verify key from Data Cloud matches your environment variable
  • Incorrect encoding: Base64 vs hex mismatch
    • ✅ Match Salesforce configuration (check Data Cloud webhook settings)
  • Not using constant-time comparison: Vulnerable to timing attacks
    • ✅ Use crypto.timingSafeEqual(), hmac.compare_digest(), or hash_equals()
  • Whitespace trimming: Modifies raw body, breaks signature
    • ✅ Preserve exact bytes received from Salesforce

Testing Salesforce Webhooks

Local Development with ngrok

# Install ngrok
brew install ngrok  # macOS
# Or download from ngrok.com

# Start your local webhook server on port 3000
node server.js

# In another terminal, create ngrok tunnel
ngrok http 3000

# Output: Forwarding https://abc123.ngrok.io -> http://localhost:3000

Configure in Salesforce:

  1. Copy the ngrok HTTPS URL
  2. Navigate to Data Cloud > Webhooks
  3. Set endpoint to: https://abc123.ngrok.io/webhooks/salesforce
  4. Save and test

Using Webhook Payload Generator

Visit Webhook Payload Generator:

  1. Select Salesforce from provider dropdown
  2. Choose event type (record.created, data.sync, etc.)
  3. Customize payload (edit record IDs, timestamps, field values)
  4. Enter your secret key
  5. Generate properly signed HMAC-SHA256 signature
  6. Copy complete HTTP request including headers
  7. Send to http://localhost:3000/webhooks/salesforce with curl

Example cURL Command:

curl -X POST http://localhost:3000/webhooks/salesforce \
  -H "Content-Type: application/json" \
  -H "X-Salesforce-Signature: <generated-signature>" \
  -d '{"event":{"type":"record.created","createdDate":"2025-01-24T12:00:00.000Z","replayId":123456},"data":{"payload":{"Id":"rec_abc123"}}}'

Best Practices

Security

  • Always verify signatures: Never process unverified webhooks
  • Use HTTPS only: Salesforce requires HTTPS endpoints
  • Store secrets securely: Environment variables, not hardcoded
  • Rotate secret keys: Periodic rotation improves security
  • Implement replay ID checks: Prevent duplicate processing
  • Validate payload structure: Check required fields exist before processing

Performance

  • Respond quickly: Return 200 within seconds to avoid timeouts
  • Process asynchronously: Queue events for background processing
  • Use database connection pooling: Don't create connections per request
  • Implement batching: Process multiple events together when possible

Reliability

  • Implement idempotency: Use replay IDs to prevent duplicate processing
  • Store replay IDs: Enable event replay during downtime
  • Log all events: Comprehensive logging for debugging
  • Monitor webhook health: Track delivery success rates
  • Set up alerts: Notify on high failure rates

Common Issues & Troubleshooting

Issue 1: Signature Verification Failing

Causes & Solutions:

Using wrong secret key ✅ Verify key from Data Cloud matches environment variable

Parsing JSON before verification ✅ Use raw body parser, verify signature before JSON.parse()

Incorrect encoding (base64 vs hex) ✅ Match encoding configured in Data Cloud webhook settings

Issue 2: Missing Webhooks

Causes & Solutions:

Firewall blocking ✅ Check firewall rules, allowlist Salesforce IPs

SSL certificate issues ✅ Verify certificate is valid and trusted

Endpoint returning errors ✅ Check application logs, fix bugs causing 5xx responses

Issue 3: Duplicate Events

Causes & Solutions:

No replay ID check ✅ Implement idempotency using replay ID storage

Network retries ✅ Return 200 only after successfully queuing event

Frequently Asked Questions

Q: How do I generate a secret key?

A: Navigate to Data Cloud Setup > API Access > Webhook Secret Keys, click "Generate New Secret Key," copy immediately (shown only once), and store in environment variables.

Q: Can I replay missed events?

A: Yes, use the replay ID system. Salesforce retains events for 24-72 hours (varies by configuration). Store the last successfully processed replay ID and request events after that ID on application restart.

Q: What's the difference between Change Data Capture and Platform Events?

A: Change Data Capture automatically publishes events for record changes (create/update/delete) on standard and custom objects. Platform Events are custom event definitions you create for application-specific messaging. CDC is better for data sync, Platform Events for custom workflows.

Q: How do I test without Salesforce account?

A: Use our Webhook Payload Generator to create signed test payloads with custom event data. This lets you test signature verification and event handling without Salesforce configuration.

Next Steps & Resources

Additional Resources

Salesforce Official Documentation:

Related Guides:

Testing Tools:

Conclusion

Salesforce webhooks provide a powerful real-time integration mechanism for tracking record changes, synchronizing data, and triggering workflows. By following this guide, you now know how to:

  • ✅ Set up Data Cloud webhooks with secret key generation
  • ✅ Verify webhook signatures using HMAC-SHA256
  • ✅ Implement production-ready endpoints with async processing
  • ✅ Handle Change Data Capture events and replay functionality
  • ✅ Test webhooks using ngrok or our payload generator
  • ✅ Troubleshoot common signature and delivery issues

Remember these key principles:

  1. Always verify signatures - HMAC-SHA256 prevents spoofing
  2. Respond quickly - Return 200 within seconds
  3. Process asynchronously - Queue events for reliability
  4. Implement idempotency - Use replay IDs to handle duplicates

Start building with Salesforce webhooks today, and use our Webhook Payload Generator to test your integration safely.


Sources:

Let's turn this knowledge into action

Get a free 30-minute consultation with our experts. We'll help you apply these insights to your specific situation.

Webhooks Explained: Complete Guide to HTTP Callbacks in 2025

Webhooks Explained: Complete Guide to HTTP Callbacks in 2025

Master webhooks with this comprehensive guide. Learn how webhooks work, implement secure webhook endpoints, handle common challenges, and integrate with popular platforms like Stripe, GitHub, Discord, and more.

Webhook Signature Verification: Complete Security Guide

Webhook Signature Verification: Complete Security Guide

Master webhook signature verification across HMAC-SHA256, HMAC-SHA1, RSA-SHA256, and ECDSA algorithms. Learn implementation patterns, security best practices, and avoid common mistakes with production-ready code examples.

SendGrid Webhooks: Complete Guide with Payload Examples [2025]

SendGrid Webhooks: Complete Guide with Payload Examples [2025]

Complete guide to SendGrid Event Webhooks with setup instructions, ECDSA signature verification, payload examples, and implementation code in Node.js, Python, and PHP. Learn how to track email deliveries, opens, clicks, and bounces in real-time.

Published Applications vs Application Virtualization | Complete Guide 2025

Published Applications vs Application Virtualization | Complete Guide 2025

Learn the key differences between published applications and application virtualization.

When Is MD5 Still Acceptable? Understanding Non-Security Use Cases

When Is MD5 Still Acceptable? Understanding Non-Security Use Cases

While MD5 is cryptographically broken for security purposes, it remains perfectly acceptable for specific non-security applications. Learn when MD5 is still appropriate and when you must use stronger alternatives.

How Hash Functions Verify File Integrity: A Complete Guide to Checksums

How Hash Functions Verify File Integrity: A Complete Guide to Checksums

Learn how cryptographic hash functions create digital fingerprints for files, enabling you to detect corruption and verify authenticity through checksum verification.