HollyHR Developer Docs
  • HollyHR
  • Sign in
  • Manage API keys
  • Start Here
  • Core API
  • AI and MCP
  • API Reference
  • Recipes
  • Resources
Recipe indexGitHub Actions recipesMCP smoke testSafe MCP leave bookingPeople syncTest SDK from sourceSlack who's awayGoogle Sheets exportReceive webhooks in NodeCreate person + webhookWebhook + payroll referencesPayroll readiness export
Recipes

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 recipe and expose it at a public HTTPS URL, for example:

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

2. Register the webhook

TerminalCode
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

TerminalCode
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:

Code
{ "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.
Last modified on June 24, 2026
Receive webhooks in NodeWebhook + payroll references
On this page
  • What it uses
  • 1. Start a receiver
  • 2. Register the webhook
  • 3. Create the person
  • 4. Process the event
  • Notes
JSON