Agent Skills by ALSEL
汎用ビジネス・経営⭐ リポ 38品質スコア 85/100

bamboohr-webhooks-events

BambooHR のウェブフック エンドポイントを実装し、HMAC署名検証と従業員変更イベント処理に対応します。グローバルウェブフックと権限付きウェブフックの両方に対応しており、リアルタイム従業員通知の設定、同期トリガーの実装、BambooHR ウェブフック ペイロードの処理が可能です。「bamboohr webhook」「bamboohr events」「bamboohr real-time sync」「bamboohr notifications」「bamboohr employee changes」といったフレーズで実行できます。

description の原文を見る

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".

SKILL.md 本文

BambooHR ウェブフック & イベント

概要

BambooHRは2種類のウェブフックをサポートしています: グローバルウェブフック(BambooHR管理UIで設定、フィールドのサブセット)とパーミッションウェブフック(APIで作成、APIキーユーザーがアクセスできるすべてのフィールド)。このスキルは、両方の種類の作成、検証、処理をカバーしています。

前提条件

  • ウェブフック管理権限付きのBambooHR APIキー
  • インターネットからアクセス可能なHTTPSエンドポイント
  • HMAC-SHA256署名検証用のウェブフックシークレット

手順

ステップ1: ウェブフックタイプを理解する

機能グローバルウェブフックパーミッションウェブフック
セットアップBambooHR管理UIAPI (POST /webhooks/)
フィールドアクセス標準フィールドのサブセットユーザーがアクセスできるすべてのフィールド
認証共有シークレットウェブフックごとのシークレット
署名SHA-256 HMACSHA-256 HMAC
アクションCreated、Updated、DeletedCreated、Updated、Deleted

ステップ2: API経由でパーミッションウェブフックを作成する

// POST /webhooks/ — 新しいウェブフックを登録
const webhook = await client.request<{
  id: number;
  name: string;
  privateKey: string; // HMAC検証に使用するため保存してください
}>('POST', '/webhooks/', {
  name: 'Employee Sync Webhook',
  monitorFields: [
    'firstName', 'lastName', 'jobTitle', 'department',
    'division', 'location', 'workEmail', 'status',
    'supervisor', 'hireDate', 'terminationDate',
  ],
  postFields: {
    firstName: 'firstName',
    lastName: 'lastName',
    jobTitle: 'jobTitle',
    department: 'department',
    status: 'status',
    workEmail: 'workEmail',
  },
  url: 'https://your-app.example.com/webhooks/bamboohr',
  format: 'json',
  frequency: { every: 0 }, // 0 = 即座、またはN = N分ごとにバッチ処理
  limit: { enabled: false },
});

console.log(`Webhook ID: ${webhook.id}`);
console.log(`Private Key: ${webhook.privateKey}`);
// 重要: privateKeyは安全に保管してください — これがHMACシークレットです

ステップ3: ウェブフックをリストして管理する

// GET /webhooks/ — このAPIキーのすべてのウェブフックをリスト
const 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}/ — ウェブフックの詳細を取得
const detail = await client.request<any>('GET', `/webhooks/${webhook.id}/`);

// GET /webhooks/{id}/log — ウェブフック配信ログを取得
const 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}/ — ウェブフックを削除
await client.request('DELETE', `/webhooks/${webhook.id}/`);

// GET /webhooks/monitor_fields — 監視可能なフィールドを確認
const fields = await client.request<any>('GET', '/webhooks/monitor_fields');

ステップ4: 署名検証

BambooHRはX-BambooHR-Signature(HMAC-SHA256 16進ダイジェスト)とX-BambooHR-Timestampの2つのヘッダーを送信します。

import crypto from 'crypto';

function verifyBambooHRWebhook(
  rawBody: Buffer | string,
  signature: string,
  timestamp: string,
  secret: string,
): boolean {
  // 1. 5分以上前のタイムスタンプを拒否(リプレイ攻撃対策)
  const age = Math.abs(Date.now() - parseInt(timestamp, 10) * 1000);
  if (age > 300_000) {
    console.error(`Webhook timestamp too old: ${age}ms`);
    return false;
  }

  // 2. 予想されるHMACを計算
  const payload = `${timestamp}.${rawBody.toString()}`;
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');

  // 3. タイミング安全な比較
  try {
    return crypto.timingSafeEqual(
      Buffer.from(signature, 'hex'),
      Buffer.from(expected, 'hex'),
    );
  } catch {
    return false;
  }
}

ステップ5: ウェブフックハンドラ(Express.js)

import express from 'express';

const app = express();

app.post('/webhooks/bamboohr',
  express.raw({ type: 'application/json' }),
  async (req, res) => {
    const sig = req.headers['x-bamboohr-signature'] as string;
    const ts = req.headers['x-bamboohr-timestamp'] as string;

    if (!sig || !ts || !verifyBambooHRWebhook(req.body, sig, ts, process.env.BAMBOOHR_WEBHOOK_SECRET!)) {
      console.error('Webhook signature verification failed');
      return res.status(401).json({ error: 'Invalid signature' });
    }

    // ウェブフックペイロードをパース
    const payload = JSON.parse(req.body.toString());
    // すぐに応答 — 非同期で処理
    res.status(200).json({ received: true });

    // ペイロード内の各従業員を処理
    await processWebhookPayload(payload);
  },
);

ステップ6: ウェブフックペイロードを処理する

BambooHRウェブフックペイロードには、アクションタイプ別にグループ化された従業員データが含まれています。

interface BambooHRWebhookPayload {
  employees: {
    id: string;
    action: 'Created' | 'Updated' | 'Deleted';
    changedFields: string[];    // この通知をトリガーしたフィールド
    fields: Record<string, string>; // 現在のフィールド値(postFields設定から)
  }[];
}

async function processWebhookPayload(payload: BambooHRWebhookPayload): Promise<void> {
  for (const employee of payload.employees) {
    const { id, action, changedFields, fields } = employee;

    switch (action) {
      case 'Created':
        console.log(`New employee: ${fields.firstName} ${fields.lastName} (ID: ${id})`);
        await onEmployeeCreated(id, fields);
        break;

      case 'Updated':
        console.log(`Employee ${id} updated: ${changedFields.join(', ')}`);

        // 何が変更されたかに基づいて特定のハンドラにルーティング
        if (changedFields.includes('department') || changedFields.includes('jobTitle')) {
          await onPositionChanged(id, fields);
        }
        if (changedFields.includes('status')) {
          if (fields.status === 'Inactive') {
            await onEmployeeTerminated(id, fields);
          }
        }
        if (changedFields.includes('supervisor')) {
          await onManagerChanged(id, fields);
        }
        break;

      case 'Deleted':
        console.log(`Employee ${id} deleted`);
        await onEmployeeDeleted(id);
        break;
    }
  }
}

// 例: ハンドラ
async function onEmployeeCreated(id: string, fields: Record<string, string>) {
  // 外部システムでアカウントをプロビジョニング
  // 例: Slackアカウント作成、メール設定、トレーニング割り当て
}

async function onEmployeeTerminated(id: string, fields: Record<string, string>) {
  // デプロビジョニング: アカウント無効化、アクセス取り消し、データアーカイブ
}

async function onPositionChanged(id: string, fields: Record<string, string>) {
  // 組織図、Slackチャンネル、アクセスグループを更新
}

async function onManagerChanged(id: string, fields: Record<string, string>) {
  // ダウンストリームシステムのレポーティング階層を更新
}

async function onEmployeeDeleted(id: string) {
  // 外部システムから削除
}

ステップ7: 冪等性(重複処理の防止)

import { Redis } from 'ioredis';

const redis = new Redis(process.env.REDIS_URL);

async function deduplicateWebhook(
  employeeId: string,
  action: string,
  changedFields: string[],
): Promise<boolean> {
  // この特定の変更のための一意のキーを作成
  const changeKey = `bamboohr:webhook:${employeeId}:${action}:${changedFields.sort().join(',')}`;
  const wasSet = await redis.set(changeKey, '1', 'EX', 3600, 'NX'); // 1時間のTTL
  return wasSet === 'OK'; // true = 初回、false = 重複
}

ステップ8: ウェブフックをローカルでテストする

# 1. ngrokでローカルサーバーを公開
ngrok http 3000
# https:// URLを注意してください

# 2. ngrok URLを指すテストウェブフックを作成
# APIを使用してngrok URLでウェブフックを作成

# 3. またはテストペイロードを手動で送信
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"}}]}'

出力

  • 監視対象フィールドを持つBambooHR API経由でウェブフックが登録されました
  • すべての受信ウェブフックに対するHMAC-SHA256署名検証
  • アクションタイプ別のイベントルーティング(Created、Updated、Deleted)
  • フィールド固有の変更ハンドラ(職位、ステータス、マネージャー)
  • Redis経由の重複排除
  • ngrokを使用したローカルテストワークフロー

エラーハンドリング

問題原因解決方法
無効な署名間違ったウェブフックシークレットウェブフック作成時のprivateKeyを確認してください
空のchangedFieldsCreated/Deletedアクション通常 — UpdatedアクションのみがchangedFieldsを含みます
ペイロードで見つからないフィールドpostFields設定に含まれていないウェブフックpostFields設定を更新してください
ウェブフックが発火しないウェブフック無効またはURL到達不可APIを通じてウェブフックのステータスとログを確認してください

エンタープライズに関する考慮事項

  • HTTPS必須: BambooHRはHTTPS URLへのみ投稿します
  • 再試行動作: BambooHRは失敗した配信を再試行します。冪等性を実装してください
  • カスタムフィールド: パーミッションウェブフックはカスタムフィールドを監視できます(/meta/fields/からフィールドIDを使用)
  • バッチ頻度: frequency.everyを0より大きく設定して、複数の変更をより少ない配信にバッチ処理します

リソース

次のステップ

パフォーマンス最適化については、bamboohr-performance-tuningを参照してください。

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
ComeOnOliver
リポジトリ
ComeOnOliver/skillshub
ライセンス
MIT
最終更新
2026/5/11

Source: https://github.com/ComeOnOliver/skillshub / ライセンス: MIT

本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: ComeOnOliver · ComeOnOliver/skillshub · ライセンス: MIT