HollyHR Developer Docs
  • Developer platform
  • GitHub
  • Sign in
  • Manage API keys
  • Start Here
  • Core API
  • AI and MCP
  • API Reference
  • Integrations
  • Recipes
  • Resources
Overview5-minute quickstartSandbox and TTFCTypeScript SDKAuthentication
Start Here

TypeScript SDK

The preview TypeScript SDK wraps the public API with small, predictable helpers. It is generated from the committed OpenAPI contract, so operation metadata stays aligned with the API reference.

Install

The package name is @hollyhr/api-client. HollyHR uses a scoped public package so partners can identify the official client, while api-client keeps the meaning clear: this is the TypeScript client for the API, not the API contract itself.

Install the public preview package from npm:

TerminalCode
pnpm add @hollyhr/api-client

The inspectable SDK source, examples and versioned OpenAPI contract live at github.com/hollyhr/hollyhr-api-client. During local HollyHR development, the release source lives at packages/hollyhr-api-client. HollyHR synchronises the matching public source before publishing each immutable npm version. Regenerate and test it with:

TerminalCode
pnpm sdk:generate pnpm sdk:test pnpm sdk:examples:check pnpm sdk:build pnpm guard:sdk

pnpm guard:sdk is part of the required merge gate. It builds the package with the SDK's own tsconfig.json, runs the dedicated SDK tests, syntax-checks the packaged examples, regenerates the operation catalogue from docs/api/openapi.v1.yaml, and fails if the generated SDK output is not committed.

Before publishing a new version, HollyHR maintainers should prove the package contents:

TerminalCode
pnpm sdk:pack pnpm sdk:publish:dry

For private testing from the monorepo or a local tarball before the next npm release, use Test the SDK from source.

Publishing a new npm version requires @hollyhr organisation publish rights and npm write authentication:

TerminalCode
pnpm sdk:publish

Do not publish under a personal or unofficial scope. The package name is part of the long-term developer contract. The public source repository is the inspectable source and issue surface; the private HollyHR monorepo remains the generation and controlled publication boundary.

First call

Code
import { createHollyHrApiClient } from "@hollyhr/api-client"; const hollyhr = createHollyHrApiClient({ baseUrl: "https://{workspace}.hollyhr.com/api/v1", token: process.env.HOLLYHR_API_TOKEN!, }); const people = await hollyhr.get("/people", { query: { limit: 10 } }); console.log({ requestId: people.requestId, rateLimit: people.rateLimit, data: people.data, });

The package ships the same first-call flow as a runnable example:

TerminalCode
export HOLLYHR_API_BASE_URL="https://{workspace}.hollyhr.com/api/v1" export HOLLYHR_API_TOKEN="hhr_live_..." node node_modules/@hollyhr/api-client/examples/first-call.mjs

Pagination

Code
for await (const person of hollyhr.paginate("/people", { query: { limit: 50 } })) { console.log(person); }

Runnable package example:

TerminalCode
node node_modules/@hollyhr/api-client/examples/paginate-people.mjs

Safe writes

Use idempotency keys for writes and If-Match for conditional updates:

Code
import { createIdempotencyKey } from "@hollyhr/api-client"; await hollyhr.patch("/people/{personId}", { pathParams: { personId: "person_..." }, ifMatch: '"etag-from-read"', idempotencyKey: createIdempotencyKey("update_person"), body: { job_title: "People Lead" }, });

SDK responses expose the write-safe HollyHR-Resource-ETag as response.etag. A standard strong ETag is accepted as a compatibility fallback, while a weak cache-only ETag is never returned as a safe write validator.

Runnable package example:

TerminalCode
export HOLLYHR_PERSON_ID="person_..." export HOLLYHR_JOB_TITLE="People Lead" node node_modules/@hollyhr/api-client/examples/safe-update-person.mjs

Governed time-off decisions

The published 0.1.0-preview.5 catalogue includes approveTimeOff and declineTimeOff, and npm latest points at that version. Both operations require an explicitly granted time_off:write scope, the current write-safe resource validator in If-Match, and an idempotency key. The packaged example reads the current record first and stops rather than making an unconditional decision:

TerminalCode
export HOLLYHR_TIME_OFF_ID="time_off_..." export HOLLYHR_TIME_OFF_DECISION="approve" # or decline # Optional for decline only: # export HOLLYHR_TIME_OFF_RESPONSE_NOTE="Private note of up to 512 characters" node node_modules/@hollyhr/api-client/examples/governed-time-off-decision.mjs

0.1.0-preview.5 is npm latest. Its matching public source and versioned OpenAPI contract are tagged at v0.1.0-preview.5. The npm package links directly to that public repository, its GitHub issue tracker and this SDK guide.

HOLLYHR_TIME_OFF_RESPONSE_NOTE is accepted only for a decline, is limited to 512 characters, and is never included in the public time-off projection, webhook payload, or audit details.

Webhook signatures

Code
import { verifyWebhookSignature } from "@hollyhr/api-client"; const valid = await verifyWebhookSignature({ payload: rawBody, secret: process.env.HOLLYHR_WEBHOOK_SECRET!, webhookIdHeader: request.headers.get("hollyhr-webhook-id")!, timestampHeader: request.headers.get("hollyhr-webhook-timestamp")!, signatureHeader: request.headers.get("x-hollyhr-signature")!, });

Reject deliveries when signature verification returns false, then use the API to fetch the current resource state if your integration needs more than the webhook notification payload.

Runnable package example:

TerminalCode
export HOLLYHR_WEBHOOK_SECRET="whsec_..." export HOLLYHR_WEBHOOK_PAYLOAD_PATH="./payload.json" export HOLLYHR_WEBHOOK_SIGNATURE="v1=..." export HOLLYHR_WEBHOOK_TIMESTAMP="2026-06-23T12:00:00.000Z" node node_modules/@hollyhr/api-client/examples/verify-webhook-signature.mjs
Last modified on October 6, 2026
Sandbox and TTFCAuthentication
On this page
  • Install
  • First call
  • Pagination
  • Safe writes
    • Governed time-off decisions
  • Webhook signatures
TypeScript
TypeScript
TypeScript
TypeScript