# Webhook listener and payroll references

Use this recipe when a payroll, finance, or HR-ops workflow needs to react to
safe HollyHR changes without receiving raw payroll, bank, tax, government-id,
date-of-birth, or home-address values.

Webhook payloads are notifications. Payroll readiness data is fetched
separately through the export endpoint with the elevated
`payroll_exports:read` scope.

## What it uses

- `POST /webhooks`
- `POST /webhooks/{webhookId}/test`
- signed webhook deliveries
- `GET /people/{personId}` or `GET /time-off/{timeOffId}` for current state
- optional `GET /payroll-readiness-export`

## Scopes

Webhook setup needs:

```text
webhooks:manage people:read time_off:read
```

The payroll readiness export needs a separate key or separately approved scope:

```text
payroll_exports:read
```

Keep `payroll_exports:read` off the webhook receiver unless that same service
is explicitly approved to fetch the readiness package.

## Register a listener

```bash
curl -X POST "$HOLLYHR_API_BASE_URL/webhooks" \
  -H "Authorization: Bearer $HOLLYHR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: idem_create_payroll_listener_001" \
  --data '{
    "name": "Payroll readiness listener",
    "url": "https://payroll-sync.example.com/hollyhr/webhooks",
    "subscribed_events": [
      "person.created",
      "person.updated",
      "person.ended",
      "person.reactivated",
      "time_off.created",
      "time_off.updated",
      "time_off.cancelled"
    ]
  }'
```

Store the returned `signing_secret` immediately. It is shown once.

## Listener behavior

1. Verify the webhook signature against the raw request body.
2. Reject stale timestamps according to your tolerance.
3. Deduplicate by `HollyHR-Webhook-Id`.
4. Acknowledge with 2xx only after safely accepting the event.
5. Fetch current state through REST if the event affects your downstream view.

Use [Receive webhooks in Node](/node-webhook-receiver) for a minimal Express
receiver and [Webhooks](/webhooks) for retry, health, delivery-log, and
redelivery details.

## Payroll readiness handoff

The payroll readiness export is provider-neutral. It returns the
`hollyhr-payroll-readiness-export` v1 package with operational identity,
employment, org-unit, working-time, FTE, readiness gap fields, a manifest, and a
README. It deliberately returns presence/gap flags rather than raw salary,
bank, NI/tax/government-id, date-of-birth, or home-address values.

Fetch it only in an approved server-side job:

```bash
curl "$HOLLYHR_API_BASE_URL/payroll-readiness-export" \
  -H "Authorization: Bearer $HOLLYHR_PAYROLL_EXPORT_TOKEN" \
  -H "Accept: application/json"
```

Use [Payroll readiness export](/reference/exports/payroll-readiness-export/guide)
for the exact contract and boundaries.

## Boundaries

- This is not a native payroll-provider connector.
- Public API webhooks currently emit for successful public API-origin writes,
  not every UI-origin change inside HollyHR.
- Webhook delivery logs never return payload bodies, response bodies,
  signatures, signing secrets, or raw delivery payload data.
- Payroll-ready does not mean payroll-certified. Treat the package as a safe
  handoff pack until HollyHR ships a named payroll connector or dedicated
  payroll-financial export.
