# Test the SDK from source

The official TypeScript SDK package is `@hollyhr/api-client`. HollyHR
maintainers and design partners can test unreleased SDK changes from the
monorepo package or a local tarball before the next npm release.

Use this recipe only for server-side Node, Next.js, worker, or integration
scripts. Do not put HollyHR API tokens in browser code.

## Option A: workspace package

Inside the HollyHR monorepo, depend on the local package through the workspace:

```json
{
  "dependencies": {
    "@hollyhr/api-client": "workspace:*"
  }
}
```

Then build and test from the repository:

```bash
pnpm sdk:generate
pnpm sdk:test
pnpm sdk:build
pnpm guard:sdk
```

`pnpm guard:sdk` checks the generated operation catalogue against
`docs/api/openapi.v1.yaml` so SDK usage stays aligned with the public contract.

## Option B: local package tarball

For a separate private app before the next npm release, ask a HollyHR maintainer
for a tarball produced from the current branch:

```bash
pnpm sdk:pack
```

Install the generated `.tgz` file in your private test app:

```bash
pnpm add ./hollyhr-api-client-0.0.0.tgz
```

Treat the tarball as preview build output. Rebuild it whenever the OpenAPI
contract or SDK source changes.

Do not publish or distribute the SDK under a personal npm scope. The public
package is `@hollyhr/api-client`; unpublished test builds should stay as
workspace dependencies or private tarballs.

## First call

```ts
import { createHollyHrApiClient } from "@hollyhr/api-client";

const hollyhr = createHollyHrApiClient({
  baseUrl: process.env.HOLLYHR_API_BASE_URL!,
  token: process.env.HOLLYHR_API_TOKEN!,
  userAgent: "acme-people-sync/0.1",
});

const people = await hollyhr.get("/people", { query: { limit: 25 } });

console.log({
  requestId: people.requestId,
  rateLimit: people.rateLimit,
  count: people.data.data.length,
});
```

## Pagination

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

## Writes

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

```ts
import { createIdempotencyKey } from "@hollyhr/api-client";

await hollyhr.patch("/people/{personId}", {
  pathParams: { personId: "person_..." },
  ifMatch: '"etag-from-get-response"',
  idempotencyKey: createIdempotencyKey("update_person"),
  body: {
    job_title: "People Lead",
  },
});
```

The SDK is a transport helper. It does not widen API scopes, bypass
idempotency, or enable MCP writes. For webhook receivers, use
[Receive webhooks in Node](/node-webhook-receiver) as the live signing
reference and fetch current resource state through REST when the notification
payload is not enough.
