> For the complete documentation index, see [llms.txt](https://docs.nerovasystems.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nerovasystems.com/sdks/available-sdks/typescript.md).

# Use the TypeScript SDK

Call the Nerova API from Node.js with the official TypeScript SDK: a typed client generated from the committed OpenAPI contract the server publishes.

Call the Nerova API from Node.js with `@nerova/sdk`: a typed client generated with [Microsoft Kiota](https://learn.microsoft.com/openapi/kiota/) from the same committed OpenAPI contract the server publishes. Every path, parameter, and model in the client exists because the contract says so.

## Prerequisites

{% hint style="info" %}

* Node.js 24 or later (the package declares `"engines": { "node": ">=24" }`; the client uses the built-in Fetch API).
* A Live API key (`nrv_live_`) from the [Quickstart](https://docs.nerovasystems.com/getting-started/quickstart).
* **The SDK is published to the public npm registry as `@nerova/sdk`** **`0.3.0-preview.1`**, a preview release: the API surface may change before 1.0.
  {% endhint %}

## 1. Install the SDK

Add the preview package from the public npm registry:

```bash
npm install @nerova/sdk@0.3.0-preview.1
```

Pin the exact version. The install brings in the Kiota runtime packages (`@microsoft/kiota-abstractions`, `@microsoft/kiota-http-fetchlibrary`, and the serialization libraries) as regular dependencies, so the imports below resolve without anything extra. This is a server-side client: keep your API key out of browsers and client bundles.

## 2. Construct the client

```typescript
import { ApiKeyAuthenticationProvider, ApiKeyLocation } from "@microsoft/kiota-abstractions";
import { FetchRequestAdapter } from "@microsoft/kiota-http-fetchlibrary";
import { createNerovaPartnerClient } from "@nerova/sdk";

const value = process.env.NEROVA_API_KEY;
if (!value) throw new Error("NEROVA_API_KEY is required");

const authenticationProvider = new ApiKeyAuthenticationProvider(
  `Bearer ${value}`,
  "Authorization",
  ApiKeyLocation.Header,
);
const client = createNerovaPartnerClient(new FetchRequestAdapter(authenticationProvider));
```

Two things to know:

* **Read the key from the environment.** Never hard-code it; the value is shown once at creation and cannot be retrieved again.
* **No base URL needed.** The client defaults to the single public host `https://api.nerovasystems.com`. Every key is a Live key (`nrv_live_`); there is no separate test host. See [Authentication](https://docs.nerovasystems.com/getting-started/authentication#api-keys).

The client mirrors the URL structure of the API: `client.api.v1.status`, `client.api.v1.context`, `client.api.v1.tenants`, and `client.api.v1.tenants.byTenantId(id)` for everything under one tenant (activation, capabilities, conversations, work, and the rest).

## 3. Make your first calls

```typescript
const status = await client.api.v1.status.get();
console.log(`API ${status?.apiVersion} (${status?.environment})`);

const context = await client.api.v1.context.get();
console.log(`environment: ${context?.environment}`);
console.log(`scopes: ${context?.grantedScopes?.join(", ")}`);

const tenants = await client.api.v1.tenants.get();
for (const tenant of tenants ?? []) {
  console.log(`${tenant.id}: ${tenant.displayName} (${tenant.provisioningState})`);
}
```

`GET /api/v1/tenants` returns a plain array of the tenants your key can see: `id`, `externalReference`, `displayName`, `provisioningState`, `lifecycleState`, `pendingStep`, `lastErrorCode`, and `version`.

## 4. Read a tenant's activation manifest

Take a tenant from the list above (or create one in step 5) and read its manifest:

```typescript
const tenantId = tenants?.[0]?.id;
if (!tenantId) throw new Error("Create a tenant first.");

const manifest = await client.api.v1.tenants
  .byTenantId(tenantId)
  .activation.manifest.get();

console.log(`what still blocks activation:`);
for (const reason of manifest?.blockingReasons ?? []) {
  console.log(`${reason.code}: ${reason.detail}`);
}
```

The activation manifest is the heart of onboarding: it tells you exactly what still blocks a tenant from going live. The full walkthrough is [Provision and activate tenants](https://docs.nerovasystems.com/guides/partner-playbook).

## 5. Create a tenant

Mutations take an `Idempotency-Key` header, a caller-owned value that makes retries safe. Derive it from your own command identity as described in [Handle errors and retries](https://docs.nerovasystems.com/guides/error-handling#make-writes-safe-with-idempotency-keys):

```typescript
const created = await client.api.v1.tenants.post(
  {
    displayName: "Demo Salon",
    externalReference: "your-crm-id-123",
  },
  { headers: { "Idempotency-Key": "provision-tenant-your-crm-id-123" } },
);

console.log(`tenant ${created?.id}: ${created?.provisioningState}`);
```

Replaying the same request with the same key returns the original result instead of creating a duplicate.

## 6. Handle errors

Failed calls throw the parsed [RFC 9457 problem document](https://docs.nerovasystems.com/api/conventions#errors) itself, a plain object, **not** an `Error` instance, so match on its fields rather than `instanceof`:

```typescript
const [tenant] = (await client.api.v1.tenants.get()) ?? [];
try {
  await client.api.v1.tenants.byTenantId(tenant!.id!).conversations.get();
} catch (error) {
  const problem = error as {
    title?: string;
    detail?: string;
    responseStatusCode?: number;
    additionalData?: { code?: string; correlationId?: string };
  };

  // Branch on stable fields, never on message text.
  if (problem.responseStatusCode === 429) {
    // schedule a bounded retry
  } else if (problem.additionalData?.code === "partner.merchant_not_available") {
    // this tenant is not granted to your key
  } else {
    console.error(
      `Nerova call failed: ${problem.additionalData?.code}` +
        ` (correlation ${problem.additionalData?.correlationId})`,
    );
  }
}
```

Quote the `correlationId` in [support reports](https://docs.nerovasystems.com/resources/support). The HTTP pipeline automatically retries `429`, `503`, and `504` responses a bounded number of times, honoring `Retry-After`; every other failure surfaces immediately, and broader retry policy stays in your hands, following [Handle errors and retries](https://docs.nerovasystems.com/guides/error-handling).

## 7. Read runtime state

Runtime surfaces (conversations, work ledger, notifications, incidents) read live merchant state for tenants your key is granted; other tenants return `partner.merchant_not_available`. Cursor-paginated endpoints all follow the same shape: pass `limit` and `cursor`, read `items` and `nextCursor`:

```typescript
let cursor: string | undefined;
do {
  const page = await client.api.v1.tenants
    .byTenantId(tenantId)
    .work.get({ queryParameters: { limit: 50, cursor } });

  for (const item of page?.items ?? []) process(item);
  cursor = page?.nextCursor ?? undefined;
} while (cursor);
```

Follow `nextCursor` until the server stops returning one.

## Keep the client current

The client is a deterministic output of the published contract. When the contract grows, a new package version ships on npm. Update by bumping the pinned version:

```bash
npm install @nerova/sdk@latest
```

Newly published operations appear as new request builders. Clients must ignore unknown response fields: [additive change is allowed](https://docs.nerovasystems.com/api/conventions#versioning).

## Next steps

* The pipeline these calls implement: [Provision and activate tenants](https://docs.nerovasystems.com/guides/partner-playbook).
* Retry and conflict policy to wrap around the client: [Handle errors and retries](https://docs.nerovasystems.com/guides/error-handling).
* Prefer another language? [Use the .NET SDK](/sdks/available-sdks/dotnet.md), [Use the Python SDK](/sdks/available-sdks/python.md), [Use the PHP SDK](/sdks/available-sdks/php.md), or [Use the Go SDK](/sdks/available-sdks/go.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nerovasystems.com/sdks/available-sdks/typescript.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
