# Breezy HR Webhooks

Breezy HR is a recruiting / applicant tracking system. It POSTs a JSON event to
your HTTPS endpoint when candidates, positions and team notes change. Webhooks
are available on Pro plans and are managed through the Breezy API.

## When to Use This Skill

* How do I receive Breezy HR webhooks?
* How do I verify the Breezy HR `X-Hook-Signature` header?
* Why is my Breezy HR webhook signature verification failing?
* How do I handle `candidateAdded` or `candidateStatusUpdated` events?
* Do I strip the `whsec_` prefix from the Breezy HR secret? (No.)

## Signature Verification (core)

| Item | Value |
| --- | --- |
| Header | `X-Hook-Signature` (also sent: `X-Breezy-Webhook-Version`) |
| Algorithm | HMAC-SHA256, hex digest, no prefix |
| Signed content | The raw request body |
| Key | The **whole** `whsec_...` secret as a UTF-8 string |

The secret only looks like a Standard Webhooks / Svix secret. Do **not** use the
`standardwebhooks` or `svix` libraries, and do not strip or base64-decode the
`whsec_` prefix.

```javascript
const crypto = require('crypto');

function verifyBreezySignature(rawBody, signature, secret) {
  if (!signature) return false;
  const expected = crypto
    .createHmac('sha256', secret) // whole whsec_ string, UTF-8
    .update(rawBody)              // raw bytes, not JSON.stringify(req.body)
    .digest('hex');
  const a = Buffer.from(signature.trim().toLowerCase());
  const b = Buffer.from(expected);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

```

Breezy's own code samples re-serialize the parsed JSON, but their
troubleshooting section says the signature covers the raw body. Use the raw
body: with Express that means `express.raw({ type: '*/*' })`, so verification
works whatever `Content-Type` arrives.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/breezy-hr-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/breezy-hr-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/breezy-hr-webhooks/examples/fastapi/).

## Common Event Types

Every payload is an envelope: `{ "_id", "type", "object", "creation_date" }`.

| Event (`type`) | Triggered When |
| --- | --- |
| `candidateAdded` | A candidate enters the system (applied, sourced, recruited, referred) |
| `candidateStatusUpdated` | A candidate moves to a different pipeline stage |
| `candidateDeleted` | A candidate is deleted in the web app |
| `companyPositionAdded` | A position is created |
| `companyPositionUpdated` | Position details change |
| `companyPositionDeleted` | A position is deleted |
| `companyPositionStateUpdated` | Position state changes (draft, published, closed...) |
| `companyNotePosted` | A team discussion note is posted |
| `companyNoteUpdated` | A team discussion note is edited |
| `companyNoteDeleted` | A team discussion note is deleted |

Deduplicate on the envelope `_id`; Breezy can occasionally deliver an event more
than once. Respond with a 2xx within 30 seconds; failures are retried up to 10
times with exponential backoff.

## Environment Variables

```bash
BREEZY_HR_WEBHOOK_SECRET=whsec_your_secret   # returned once when you create the endpoint

```

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 breezy-hr --path /webhooks/breezy-hr

```

Breezy only accepts public HTTPS URLs (no localhost), so use the tunnel URL when
creating the webhook endpoint.

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/breezy-hr-webhooks/references/overview.md) - Breezy HR webhook concepts and events
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/breezy-hr-webhooks/references/setup.md) - Create an endpoint and get the secret
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/breezy-hr-webhooks/references/verification.md) - Signature details and gotchas