# Create a person and receive a webhook

This recipe shows the smallest end-to-end write workflow: create a safe person
record through the API, then receive the signed `person.created` webhook.

Use this when you want an external system to create starter people records in
HollyHR and react once HollyHR accepts the write. The API does not accept
compensation, bank details, tax or government identifiers, home contact data,
dates of birth, demographics, notes, avatar bytes, or document bytes in this
flow.

## What it uses

- `POST /webhooks`
- `POST /people`
- the `person.created` webhook event

The API key needs `people:write`, `people:read`, and `webhooks:manage`.
`people:read` is required because webhook event subscriptions are checked
against the read scope for the event payload they may receive.

## 1. Start a receiver

Use the [Node webhook receiver](/node-webhook-receiver) recipe and expose it at
a public HTTPS URL, for example:

```text
https://your-public-tunnel.example.com/hollyhr/webhooks
```

## 2. Register the webhook

```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_person_webhook_001" \
  --data '{
    "name": "People setup webhook",
    "url": "https://your-public-tunnel.example.com/hollyhr/webhooks",
    "subscribed_events": ["person.created"]
  }'
```

Store the returned `signing_secret` in your receiver as
`HOLLYHR_WEBHOOK_SECRET`. The secret is shown once.

## 3. Create the person

```bash
curl -X POST "$HOLLYHR_API_BASE_URL/people" \
  -H "Authorization: Bearer $HOLLYHR_API_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: idem_create_person_amelia_watts_001" \
  --data '{
    "work_email": "amelia.watts@example.com",
    "first_name": "Amelia",
    "last_name": "Watts",
    "job_title": "Operations Coordinator",
    "start_date": "2026-07-01"
  }'
```

The response is the safe person projection. Reusing the same
`Idempotency-Key` with the exact same request returns the same result. Reusing
it with a different body returns an idempotency conflict.

## 4. Process the event

Your receiver will receive a signed event shaped like:

```json
{
  "id": "evt_...",
  "type": "person.created",
  "api_version": "v1",
  "occurred_at": "2026-06-18T09:00:00.000Z",
  "data": {
    "id": "per_...",
    "resource_type": "person"
  }
}
```

Treat webhook delivery as at-least-once. Store the `HollyHR-Webhook-Id` before
side effects so retries are safe.

## Notes

- API-created people are active starter records; this flow does not send invite
  emails.
- UI-origin changes inside HollyHR do not currently emit public API webhooks
  just because the same event type exists for public API-origin writes.
- If you need the full current person projection after receiving the event,
  call `GET /people/{person_id}` with a key that has `people:read`.
