Agent skill
Humaans Webhooks Skill
Receive and verify Humaans (HRIS) webhooks. Use when setting up a Humaans webhook handler, debugging Standard Webhooks / Svix signature verification (webhook-signature, whsec_ secret), or handling person.created, person.offboarded, timeAway.approved and compensation.updated events.
Install this skill
npx skills add hookdeck/webhook-skills --skill humaans-webhooks
Humaans is an HR information system (HRIS). Its webhooks tell you when people, time away, compensation, job roles, bank accounts, emergency contacts and equipment change, so you can sync payroll, IT provisioning and directories without polling. Webhooks are created by an Owner and delivered through Svix.
When to Use This Skill
- How do I receive Humaans webhooks?
- How do I verify Humaans webhook signatures (
webhook-signature,whsec_secret)? - How do I handle
person.created,person.offboardedortimeAway.approvedevents? - Where do I get the Humaans webhook signing secret?
- Why is my Humaans webhook signature verification failing?
Verification (core)
Humaans deliveries follow Standard Webhooks: webhook-id, webhook-timestamp (Unix seconds) and webhook-signature (space-delimited v1,<base64> entries). Svix can send the same values as svix-id, svix-timestamp and svix-signature, so accept either prefix. The signature is base64 HMAC-SHA256 over {id}.{timestamp}.{raw body}, keyed with the base64-decoded part of the whsec_... secret.
Use the standardwebhooks library (Node and Python). It throws on a bad signature or a timestamp more than 5 minutes off, and returns the parsed payload:
const { Webhook } = require('standardwebhooks'); // Python: from standardwebhooks.webhooks import Webhook
const h = (name) => req.headers[`webhook-${name}`] ?? req.headers[`svix-${name}`];
const event = new Webhook(process.env.HUMAANS_WEBHOOK_SECRET).verify(rawBody, {
'webhook-id': h('id'),
'webhook-timestamp': h('timestamp'),
'webhook-signature': h('signature'),
});
Verify against the raw body before parsing JSON (in Express use express.raw({ type: '*/*' }) so any content type is read raw).
Timestamp window and Hookdeck. The standardwebhooks and svix libraries always enforce a fixed 5-minute timestamp window, and it can't be turned off. Hookdeck retries and replays resend the original webhook-timestamp, so the library rejects them once they are more than 5 minutes old. If you receive through Hookdeck and need late retries and replays to pass, use the manual verifier in references/verification.md (HMAC-SHA256 over {id}.{timestamp}.{raw body}, key = base64-decoded secret after whsec_, every space-separated v1,<base64> entry compared in constant time), where the window can be dropped or widened.
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Common Event Types
The body is an event wrapper (id, seq, ts, action, subject, actor, entity); dispatch on action.
Event (action) | Sent when |
|---|---|
person.created | A person is added |
person.updated | A person's profile changes |
person.offboarded | A person is offboarded (person.reonboarded when they return) |
timeAway.created | A time away request is created (also .updated, .deleted, .rejected) |
timeAway.approved | A time away request is approved |
compensation.updated | A compensation record changes (also .created, .deleted) |
Other actions: person.deleted, timeAwayAdjustment.*, bankAccount.*, jobRole.*, emergencyContact.*, equipment.* (each created, updated, deleted). See references/overview.md.
Important Headers
| Header | Description |
|---|---|
webhook-id (or svix-id) | Message ID; unchanged on retries, use it for idempotency |
webhook-timestamp (or svix-timestamp) | Unix seconds of this delivery attempt |
webhook-signature (or svix-signature) | v1,<base64> entries, space-delimited (several during secret rotation) |
Environment Variables
HUMAANS_WEBHOOK_SECRET=whsec_xxxxx # prodEndpointSignature of the webhook, e.g. whsec_vwbddlgH8lyKqHEDzn3EUpmk
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 humaans --path /webhooks/humaans
Use the printed URL as the webhook's production endpoint URL, then publish the webhook so Humaans starts delivering. Any 2xx response is a success; other responses are retried with exponential backoff.
Reference Materials
- references/overview.md - What Humaans webhooks are, events, payload, delivery behaviour
- references/setup.md - Create and publish a webhook in Humaans or via the API, get the signing secret
- references/verification.md - Signature verification details, manual Node/Python verifiers, gotchas