Implement BambooHR webhook endpoints with HMAC signature validation
and employee change event handling. Covers global and permissioned webhooks.
Use when setting up real-time employee notifications, implementing sync triggers,
or handling BambooHR webhook payloads.
Trigger with phrases like "bamboohr webhook", "bamboohr events",
"bamboohr real-time sync", "bamboohr notifications", "bamboohr employee changes".
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Implement BambooHR webhook endpoints with HMAC signature validation
and employee change event handling. Covers global and permissioned webhooks.
Use when setting up real-time employee notifications, implementing sync triggers,
or handling BambooHR webhook payloads.
Trigger with phrases like "bamboohr webhook", "bamboohr events",
"bamboohr real-time sync", "bamboohr notifications", "bamboohr employee changes".
allowed-tools
Read, Write, Edit, Bash(curl:*)
version
1.4.0
license
MIT
author
Jeremy Longshore <jeremy@intentsolutions.io>
tags
["saas","hr","bamboohr","webhooks"]
compatibility
Designed for Claude Code
BambooHR Webhooks & Events
Overview
BambooHR supports two webhook types: global webhooks (configured in the BambooHR admin UI, subset of fields) and permissioned webhooks (created via API, access all fields the API key user can see). This skill covers creating, validating, and handling both types.
Prerequisites
BambooHR API key with webhook management permissions
HTTPS endpoint accessible from the internet
Webhook secret for HMAC-SHA256 signature verification
// IMPORTANT: Store the privateKey securely — it's the HMAC secret
Step 3: List and Manage Webhooks
// GET /webhooks/ — list all webhooks for this API keyconst webhooks = await client.request<any[]>('GET', '/webhooks/');
for (const wh of webhooks) {
console.log(`${wh.id}: ${wh.name} -> ${wh.url} (${wh.status})`);
}
// GET /webhooks/{id}/ — get webhook detailsconst detail = await client.request<any>('GET', `/webhooks/${webhook.id}/`);
// GET /webhooks/{id}/log — get webhook delivery logsconst logs = await client.request<any[]>('GET', `/webhooks/${webhook.id}/log`);
for (const log of logs) {
console.log(`${log.timestamp}: ${log.statusCode} (${log.employeeId})`);
}
// DELETE /webhooks/{id}/ — remove a webhookawait client.request('DELETE', `/webhooks/${webhook.id}/`);
// GET /webhooks/monitor_fields — see available fields to monitorconst fields = await client.request<any>('GET', '/webhooks/monitor_fields');
Step 4: Signature Verification
BambooHR sends two headers: X-BambooHR-Signature (HMAC-SHA256 hex digest) and X-BambooHR-Timestamp.
import { Redis } from'ioredis';
const redis = newRedis(process.env.REDIS_URL);
asyncfunctiondeduplicateWebhook(employeeId: string,
action: string,
changedFields: string[],
): Promise<boolean> {
// Create a unique key for this specific changeconst changeKey = `bamboohr:webhook:${employeeId}:${action}:${changedFields.sort().join(',')}`;
const wasSet = await redis.set(changeKey, '1', 'EX', 3600, 'NX'); // 1 hour TTLreturn wasSet === 'OK'; // true = first time, false = duplicate
}
Step 8: Test Webhooks Locally
# 1. Expose local server with ngrok
ngrok http 3000
# Note the https:// URL# 2. Create a test webhook pointing to your ngrok URL# Use the API to create webhook with your ngrok URL# 3. Or manually send a test payload
curl -X POST http://localhost:3000/webhooks/bamboohr \
-H "Content-Type: application/json" \
-H "X-BambooHR-Timestamp: $(date +%s)" \
-H "X-BambooHR-Signature: test" \
-d '{"employees": [{"id":"1","action":"Updated","changedFields":["department"],"fields":{"firstName":"Jane","department":"Engineering"}}]}'
Output
Webhook registered via BambooHR API with monitored fields
HMAC-SHA256 signature verification on all incoming webhooks
Event routing by action type (Created, Updated, Deleted)