> ## Documentation Index
> Fetch the complete documentation index at: https://docs.nvisy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Complete TypeScript SDK API reference

## Nvisy

The client class. All services are exposed as lazily-constructed properties.

```typescript theme={null}
import { Nvisy } from "@nvisy/sdk";

const client = new Nvisy({ apiToken: process.env.NVISY_API_TOKEN! });
```

The constructor takes a single `ClientConfig` object.

### ClientConfig

| Property      | Type                     | Required | Default                  | Description                       |
| ------------- | ------------------------ | -------- | ------------------------ | --------------------------------- |
| `apiToken`    | `string`                 | Yes      | —                        | API token used for authentication |
| `baseUrl`     | `string`                 | No       | `https://api.nvisy.com`  | Custom API base URL               |
| `userAgent`   | `string`                 | No       | `@nvisy/sdk v.<version>` | Custom user agent                 |
| `withLogging` | `boolean`                | No       | `false`                  | Enable debug logging              |
| `headers`     | `Record<string, string>` | No       | —                        | Extra headers on every request    |

`DEFAULTS` and `VERSION` are exported for reference.

### Services

| Property        | Description                                        |
| --------------- | -------------------------------------------------- |
| `auth`          | Login, signup, logout                              |
| `account`       | The authenticated user's account                   |
| `apiTokens`     | Create and revoke API tokens                       |
| `workspaces`    | Workspace CRUD, avatars, notification settings     |
| `members`       | Workspace membership                               |
| `invites`       | Workspace invitations                              |
| `files`         | Upload, list, download, delete files               |
| `pipelines`     | Pipeline definitions                               |
| `policies`      | Detection and redaction policies                   |
| `runs`          | Pipeline runs, detections, redaction, audit export |
| `connections`   | External data source connections                   |
| `syncs`         | Connection sync jobs                               |
| `webhooks`      | Webhook endpoints                                  |
| `notifications` | User notifications                                 |
| `activities`    | Workspace activity log                             |
| `catalog`       | Available labels and recognizers                   |
| `status`        | Service health                                     |
| `api`           | Underlying typed HTTP client                       |

<Note>
  Most methods take `workspaceSlug` as their first argument. Workspaces are the
  top-level tenancy boundary.
</Note>

## Workspaces

```typescript theme={null}
listWorkspaces(query?: CursorPagination): Promise<WorkspacePage>
getWorkspace(workspaceSlug: string): Promise<Workspace>
createWorkspace(workspace: CreateWorkspace): Promise<Workspace>
updateWorkspace(workspaceSlug: string, updates: UpdateWorkspace): Promise<Workspace>
deleteWorkspace(workspaceSlug: string): Promise<void>
getNotificationSettings(workspaceSlug: string): Promise<NotificationSettings>
updateNotificationSettings(workspaceSlug: string, settings: UpdateNotificationSettings): Promise<NotificationSettings>
uploadAvatar(workspaceSlug: string, avatar: Blob): Promise<void>
deleteAvatar(workspaceSlug: string): Promise<void>
```

## Files

```typescript theme={null}
uploadFiles(workspaceSlug: string, files: Blob | Blob[]): Promise<File[]>
listFiles(workspaceSlug: string, query?: ListFiles & CursorPagination): Promise<FilePage>
getFile(workspaceSlug: string, fileId: string): Promise<File>
downloadFile(workspaceSlug: string, fileId: string): Promise<Response>
updateFile(workspaceSlug: string, fileId: string, updates: UpdateFile): Promise<File>
deleteFile(workspaceSlug: string, fileId: string): Promise<void>
```

`uploadFiles` accepts a single `Blob` or an array, and sends them as
`multipart/form-data`. `downloadFile` returns the raw `Response` so you can
stream the body.

## Pipelines

```typescript theme={null}
listPipelines(workspaceSlug: string, query?: PipelineFilter & CursorPagination): Promise<PipelineSummaryPage>
createPipeline(workspaceSlug: string, pipeline: CreatePipeline): Promise<Pipeline>
getPipeline(workspaceSlug: string, pipelineSlug: string): Promise<Pipeline>
updatePipeline(workspaceSlug: string, pipelineSlug: string, updates: UpdatePipeline): Promise<Pipeline>
deletePipeline(workspaceSlug: string, pipelineSlug: string): Promise<void>
```

## Policies

```typescript theme={null}
listPolicies(workspaceSlug: string, query?: CursorPagination): Promise<PolicyPage>
createPolicy(workspaceSlug: string, policy: CreatePolicy): Promise<Policy>
getPolicy(workspaceSlug: string, policySlug: string): Promise<Policy>
updatePolicy(workspaceSlug: string, policySlug: string, updates: UpdatePolicy): Promise<Policy>
deletePolicy(workspaceSlug: string, policySlug: string): Promise<void>
```

## Runs

```typescript theme={null}
listRuns(workspaceSlug: string, query?: PipelineRunsQuery & CursorPagination): Promise<PipelineRunPage>
listPipelineRuns(workspaceSlug: string, pipelineSlug: string, query?: PipelineRunsQuery & CursorPagination): Promise<PipelineRunPage>
createRun(workspaceSlug: string, pipelineSlug: string, run: CreatePipelineRun): Promise<PipelineRun>
getRun(workspaceSlug: string, runId: string): Promise<PipelineRun>
getDetections(workspaceSlug: string, runId: string): Promise<Audit>
redact(workspaceSlug: string, runId: string): Promise<PipelineRun>
downloadAuditJson(workspaceSlug: string, runId: string): Promise<Response>
downloadAuditCsv(workspaceSlug: string, runId: string): Promise<Response>
events(workspaceSlug: string, runId: string): Promise<Response>
```

`createRun` starts detection over a single file:

```typescript theme={null}
const run = await client.runs.createRun(workspaceSlug, pipelineSlug, {
  fileId: file.id,
});
```

`events` returns a server-sent events stream of `RunStatusEvent` values for
live progress. `redact` applies redactions once you are satisfied with the
detections.

## API Tokens

```typescript theme={null}
listApiTokens(query?: CursorPagination): Promise<ApiTokenPage>
getApiToken(tokenId: string): Promise<ApiToken>
createApiToken(token: CreateApiToken): Promise<ApiTokenWithJWT>
updateApiToken(tokenId: string, updates: UpdateApiToken): Promise<ApiToken>
revokeApiToken(tokenId: string): Promise<void>
```

<Warning>
  `createApiToken` returns the JWT exactly once. Store it immediately — it
  cannot be retrieved later.
</Warning>

## Authentication

```typescript theme={null}
loginAccount(credentials: Login): Promise<AuthToken>
signupAccount(credentials: Signup): Promise<AuthToken>
logoutAccount(): Promise<void>
```

## Pagination

List methods are cursor-paginated and accept `CursorPagination`:

| Property | Type     | Description                                           |
| -------- | -------- | ----------------------------------------------------- |
| `after`  | `string` | Cursor pointing at the last item of the previous page |
| `limit`  | `number` | Maximum items to return                               |

```typescript theme={null}
let after: string | undefined;
do {
  const page = await client.files.listFiles(workspaceSlug, { after, limit: 50 });
  for (const file of page.items) console.log(file.id);
  after = page.nextCursor;
} while (after);
```

## Errors

```typescript theme={null}
import { NvisyError, NvisyApiError } from "@nvisy/sdk";
```

`NvisyError` is the base class. `NvisyApiError` extends it for API responses:

| Property     | Type                  | Description                    |
| ------------ | --------------------- | ------------------------------ |
| `message`    | `string`              | User-facing message            |
| `statusCode` | `number`              | HTTP status code               |
| `resource`   | `string \| undefined` | Resource involved              |
| `suggestion` | `string \| undefined` | Suggested remedy               |
| `validation` | `object \| undefined` | Field-level validation details |

Helpers: `isClientError()` (4xx), `isServerError()` (5xx), `isRetryable()`.

```typescript theme={null}
try {
  await client.runs.redact(workspaceSlug, runId);
} catch (error) {
  if (error instanceof NvisyApiError) {
    if (error.isRetryable()) {
      // Retryable transport/server error. Retrying `redact` is not automatically
      // safe — the API defines no idempotency for it, so re-read the run and
      // check whether it already reached `completed` before trying again.
    }
    console.error(error.statusCode, error.message, error.suggestion);
  }
}
```

<Warning>
  `isRetryable()` reports that the *error* is of a transient kind, not that the
  *operation* is safe to repeat. Retry automatically only for reads or for
  requests carrying an idempotency key.
</Warning>

### Idempotency Keys

`createRun` accepts an `Idempotency-Key` header: repeating a request with the
same key returns the existing run instead of starting a second one. Generate one
key per logical run and reuse it across every retry of that run.

```typescript theme={null}
const idempotencyKey = crypto.randomUUID();

const run = await withRetry(() =>
  client.runs.createRun(
    workspaceSlug,
    pipelineSlug,
    { fileId: file.id },
    { headers: { "Idempotency-Key": idempotencyKey } },
  ),
);
```

<Note>
  Generating a fresh key inside the retry loop defeats the purpose — each
  attempt would then look like a new run.
</Note>
