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

```bash
pnpm add @hollyhr/api-client
```

During local HollyHR development, the source package lives at
`packages/hollyhr-api-client`. Regenerate and test it with:

```bash
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:

```bash
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](/sdk-before-npm).

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

```bash
pnpm sdk:publish
```

Do not publish under a personal or unofficial scope. The package name is part of
the long-term developer contract. HollyHR does not need a separate public GitHub
repository for the package. The SDK can be published from the private monorepo;
package metadata points developers to this documentation and support channel.

## First call

```ts
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:

```bash
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

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

Runnable package example:

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

## Safe writes

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

```ts
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" },
});
```

Runnable package example:

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

## Webhook signatures

```ts
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:

```bash
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
```
