Webhook events not triggering on candidate status change in recruiting module integration

Our webhook endpoint isn’t receiving events when candidate statuses change in ADP’s recruiting module (adp-2023.2). We’ve registered the endpoint and confirmed it’s accessible, but no events are being delivered.

Webhook registration appears successful:

{
  "webhookId": "wh_abc123",
  "endpoint": "https://our-domain.com/webhooks/adp",
  "events": ["candidate.status.changed"],
  "status": "active"
}

We’ve tested the endpoint with manual POST requests and it works fine. The webhook shows as active in ADP’s developer console, but when we change candidate statuses manually in the UI, no events arrive. We’re not sure if the issue is with event subscription configuration, endpoint registration, or event filtering. Has anyone encountered webhook delivery issues with ADP recruiting events?

Enable webhook delivery logging in ADP’s developer console if it’s available for your instance. This will show you whether ADP is attempting to deliver events and what response codes they’re receiving. If logging isn’t available, implement a simple webhook testing service like webhook.site temporarily to verify that events are being sent at all. Sometimes the issue is that events aren’t being generated in the first place due to configuration problems rather than delivery failures.

Check if your ADP instance has webhooks enabled at the tenant level. This is a setting that needs to be turned on by ADP support - it’s not enabled by default for all customers. Also verify that the user account you used to register the webhook has the necessary permissions. Webhook registration requires specific API admin permissions that regular developer accounts might not have. Contact your ADP account manager to verify both of these settings.

In adp-2023.2, candidate status change events are filtered by workflow stage. If the status change doesn’t move the candidate to a different workflow stage (e.g., changing from “Phone Screen Scheduled” to “Phone Screen Completed” within the same Interview stage), it might not trigger a webhook event. You may need to subscribe to more granular events or use polling as a fallback for status changes within the same stage. Check the event payload documentation to see what triggers actually fire webhooks versus what’s just UI state changes.

One common gotcha: SSL certificate validation. ADP requires valid SSL certificates on webhook endpoints - self-signed certificates will cause silent failures. Also check if your firewall or load balancer is blocking requests from ADP’s IP ranges. You might need to whitelist their webhook delivery servers. We had to add ADP’s IP ranges to our WAF allowlist before webhooks started working.

Your webhook issue requires systematic troubleshooting across all three critical areas:

1. Webhook Event Subscription: The event name you’re using may not be correct for adp-2023.2. ADP’s recruiting webhook events follow a specific taxonomy:

  • recruiting.candidate.created - New candidate added
  • recruiting.candidate.updated - Any candidate field updated (this is what you likely need)
  • recruiting.application.statusChanged - Application status changed (different from candidate status)
  • recruiting.candidate.workflow.transitioned - Candidate moved between workflow stages

The event name candidate.status.changed doesn’t exist in ADP’s standard event catalog. You need to subscribe to recruiting.candidate.updated which fires on any candidate record change, including status updates. However, this gives you all updates, so you’ll need to filter in your endpoint code.

Alternatively, use recruiting.candidate.workflow.transitioned if you only care about major status changes that move candidates between workflow stages (Applied → Phone Screen → Interview → Offer → Hired). Minor status updates within a stage won’t trigger this event.

Update your subscription:

{
  "webhookId": "wh_abc123",
  "endpoint": "https://our-domain.com/webhooks/adp",
  "events": [
    "recruiting.candidate.updated",
    "recruiting.candidate.workflow.transitioned"
  ],
  "status": "active",
  "filters": {
    "fieldChanges": ["status", "workflowStage"]
  }
}

Note the filters object - ADP supports filtering events by which fields changed, reducing noise at your endpoint.

2. Endpoint Registration: Your endpoint registration looks correct, but verify these requirements:

a) HTTPS with valid certificate: ADP requires TLS 1.2+ with certificates from recognized CAs. Self-signed certificates fail silently.

b) Response requirements: Your endpoint must:

  • Respond with HTTP 200-299 within 5 seconds
  • Return empty body or simple JSON acknowledgment
  • Not perform long-running processing in the request handler

c) Header validation: ADP sends webhook signature headers for security:


X-ADP-Signature: sha256=abc123...
X-ADP-Timestamp: 1620456789
X-ADP-Event-Type: recruiting.candidate.updated

Your endpoint should validate the signature to ensure requests are from ADP. If your validation logic rejects the request, events will fail.

d) IP whitelisting: ADP webhook requests come from specific IP ranges. Add these to your firewall allowlist:

  • 52.206.x.x/16 (US East)
  • 54.241.x.x/16 (US West)
  • Contact ADP support for complete current IP ranges

e) Endpoint path: Ensure your endpoint path exactly matches registration. ADP doesn’t follow redirects, so if your server redirects /webhooks/adp to /webhooks/adp/, events will fail.

3. Event Filtering: ADP’s recruiting module has complex event filtering logic:

a) Workflow stage filtering: Not all status changes trigger events. Changes must meet one of these criteria:

  • Candidate moves between major workflow stages
  • Status field explicitly marked as “webhook-enabled” in ADP configuration
  • Change made via API (UI changes may be batched or filtered)

b) Batch operation exclusion: Status changes made through bulk operations, imports, or automated workflows may not trigger individual webhook events. They might trigger a single batch event instead.

c) Permission-based filtering: Webhook events only fire for candidates the webhook registration user has permission to view. If your API user doesn’t have access to all recruiting positions, you won’t receive events for those candidates.

Diagnostic steps:

  1. Test with API-triggered changes: Instead of changing status in the UI, make a status change via API call and see if the webhook fires. This isolates whether the issue is with event generation or delivery.

  2. Check ADP webhook logs: In ADP’s developer console, navigate to Webhooks → Delivery Logs. This shows:

    • Whether events were generated
    • Delivery attempts and response codes
    • Failure reasons

    If no logs appear, events aren’t being generated (subscription issue). If logs show 4xx/5xx responses, your endpoint has problems.

  3. Implement webhook testing endpoint: Temporarily point your webhook to a service like webhook.site or requestbin.com to verify ADP is sending events. If events appear there but not at your endpoint, the issue is with your server configuration.

  4. Verify tenant-level settings: Contact ADP support to confirm:

    • Webhooks are enabled for your tenant
    • Your API user has webhook administration permissions
    • Recruiting module is configured to generate webhook events
    • No tenant-level filters are blocking events
  5. Test signature validation: Temporarily disable signature validation in your endpoint code to rule out authentication issues. If events start arriving, your signature validation logic is incorrect.

Recommended implementation:

app.post('/webhooks/adp', (req, res) => {
  // 1. Immediately respond to ADP (don't make them wait)
  res.status(200).json({ received: true });

  // 2. Validate signature asynchronously
  const signature = req.headers['x-adp-signature'];
  const timestamp = req.headers['x-adp-timestamp'];
  if (!validateSignature(req.body, signature, timestamp)) {
    logger.error('Invalid webhook signature');
    return;
  }

  // 3. Queue for async processing
  eventQueue.push({
    eventType: req.headers['x-adp-event-type'],
    payload: req.body,
    receivedAt: new Date()
  });
});

This pattern ensures you respond quickly to ADP while processing events asynchronously, preventing timeout issues.

If after these steps events still don’t arrive, open a support ticket with ADP including your webhook ID, tenant ID, and specific candidate IDs you’ve tested with. There may be tenant-specific configuration issues only they can diagnose.

First thing to check: does your endpoint return a 200 status code within 5 seconds? ADP’s webhook system has a strict timeout and will mark endpoints as failed if they don’t respond quickly. Also verify your endpoint accepts POST requests with application/json content type and doesn’t require authentication headers that ADP isn’t sending. Check your server logs to see if requests are arriving but failing validation.

ADP’s webhook events for recruiting are notoriously finicky about event subscription scope. The event name “candidate.status.changed” might be too specific or not match their exact event taxonomy. Try subscribing to a broader event like “recruiting.candidate.updated” or check their API documentation for the exact event names. Also, some status changes might not trigger events if they’re done through batch operations or imports rather than the UI. We had to subscribe to multiple event types to catch all candidate changes.