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

# StackApp

> Reference documentation for HexclaveClientApp and HexclaveServerApp objects.

This is a detailed reference for the `StackApp` object. For setup instructions, see [Setup](https://docs.hexclave.com/guides/getting-started/setup.md).

## Overview

* [HexclaveClientApp](#stackclientapp) - Client-level permissions for frontend code
* [HexclaveServerApp](#stackserverapp) - Server-level permissions with full access

***

# HexclaveClientApp

A `StackApp` with client-level permissions. It contains most of the useful methods and hooks for your client-side code.

Most commonly you get an instance of `HexclaveClientApp` by calling [`useHexclaveApp()`](https://docs.hexclave.com/sdk/hooks/use-hexclave-app) in a Client Component.

## Table of Contents

```typescript theme={null}
type HexclaveClientApp = {
  new(options): HexclaveClientApp;

  getUser([options]): Promise<User>;
  useUser([options]): User;
  getProject(): Promise<Project>;
  useProject(): Project;

  signInWithOAuth(provider): void;
  signInWithCredential([options]): Promise<...>;
  signUpWithCredential([options]): Promise<...>;
  sendForgotPasswordEmail(email): Promise<...>;
  sendMagicLinkEmail(email): Promise<...>;

  initAnalytics(): void;
};
```

## Constructor

Creates a new `HexclaveClientApp` instance.

Because each app creates a new connection to Hexclave's backend, you should re-use existing instances wherever possible.

> [!NOTE]
>
> This object is not usually constructed directly. More commonly, you would construct a [`HexclaveServerApp`](#stackserverapp) instead, pass it into your app setup (see the [setup guide](https://docs.hexclave.com/guides/getting-started/setup.md)), and then use the `useHexclaveApp()` hook to obtain a `HexclaveClientApp`.
>
> The [setup wizard](https://docs.hexclave.com/guides/getting-started/setup.md) does these steps for you, so you don't need to worry about it unless you are manually setting up Hexclave.
>
> If you're building a client-only app and don't have a `HEXCLAVE_SECRET_SERVER_KEY`, you can construct a `HexclaveClientApp` directly.

Parameters

**tokenStore** `"nextjs-cookie" | "cookie" | \{ accessToken, refreshToken \} | Request` *required*

Token storage configuration.

**baseUrl** `string`

Base URL for the Hexclave API.

**projectId** `string`

Project ID. Defaults to the `NEXT_PUBLIC_HEXCLAVE_PROJECT_ID` environment variable.

**publishableClientKey** `string`

Publishable client key. Defaults to the `NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY` environment variable.

**urls** `object`

Redirect URL configuration.

**analytics** `object`

Analytics capture configuration. SDK-managed capture is enabled by default; pass `{ enabled: false }` to disable it entirely, or `{ replays: { enabled: true } }` to record session replays.

**noAutomaticPrefetch** `boolean`

Disable automatic prefetching.

**automaticSideEffects** `boolean`

Whether construction automatically processes authentication query parameters, accesses browser storage, records analytics or session replays, installs listeners, and mounts development UI. Defaults to `true`. Explicit method calls still work normally when set to `false`.

**devTool** `boolean | "auto"`

Whether to show the [dev tool indicator](https://docs.hexclave.com/guides/other/dev-tool.md) in browser-like environments. `"auto"` (the default) shows it only in development; `true` always shows it; `false` never does.

Signature

```typescript theme={null}
declare class HexclaveClientApp {
  constructor(options: {
    tokenStore: "nextjs-cookie" | "cookie" | {
      accessToken: string;
      refreshToken: string;
    } | Request;
    baseUrl?: string;
    projectId?: string;
    publishableClientKey?: string;
    urls?: object;
    analytics?: object;
    noAutomaticPrefetch?: boolean;
    automaticSideEffects?: boolean;
    devTool?: boolean | "auto";
  });
}
```

Examples

```typescript theme={null}
const hexclaveClientApp = new HexclaveClientApp({
  tokenStore: "nextjs-cookie",
  baseUrl: "https://api.hexclave.com",
  projectId: "123",
  publishableClientKey: "123",
  urls: {
    home: "/",
  },
});
```

```typescript theme={null}
"use client";

function MyReactComponent() {
  const hexclaveClientApp = useHexclaveApp();
}
```

## User Management

### `hexclaveClientApp.getUser([options])`

Gets the current user.

Parameters

**options.or** `"return-null" | "redirect" | "throw"`

What to do if the user is not found. The `"redirect"` option is deprecated on `getUser`;
use `useUser({ or: "redirect" })` in React, or perform an explicit browser redirect after a
nullable `getUser()` call.

Returns

`Promise<CurrentUser | null>`

Signature

```typescript theme={null}
declare function getUser(options?: {
  or?: "return-null" | "redirect" | "throw";
}): Promise<CurrentUser | null>;
```

Examples

```typescript theme={null}
const userOrNull = await hexclaveClientApp.getUser();
console.log(userOrNull);
```

### `hexclaveClientApp.useUser([options])`

React hook version of `getUser()`. Equivalent to the [`useUser()`](https://docs.hexclave.com/sdk/hooks/use-user) standalone hook, which is an alias for `useHexclaveApp().useUser()`.

Parameters

**options.or** `"return-null" | "redirect" | "throw"`

What to do if the user is not found.

Returns

`CurrentUser | null`

Signature

```typescript theme={null}
declare function useUser(options?: {
  or?: "return-null" | "redirect" | "throw";
}): CurrentUser | null;
```

Examples

```jsx theme={null}
"use client";

function MyReactComponent() {
  const user = useUser();
  return user ? <div>Hello, {user.name}</div> : <div>Not signed in</div>;
}
```

```tsx theme={null}
"use client";

function MyProtectedComponent() {
  useUser({ or: "redirect" });
  return <div>You can only see this if you are authenticated</div>;
}
```

### `hexclaveClientApp.getProject()`

Gets the current project.

Returns

`Promise<Project>`

Signature

```typescript theme={null}
declare function getProject(): Promise<Project>;
```

Examples

```typescript theme={null}
const project = await hexclaveClientApp.getProject();
```

### `hexclaveClientApp.useProject()`

React hook version of `getProject()`.

Returns

`Project`

Signature

```typescript theme={null}
declare function useProject(): Project;
```

Examples

```typescript theme={null}
function MyReactComponent() {
  const project = useProject();
}
```

## Authentication

### `hexclaveClientApp.signInWithOAuth(provider)`

Initiates the OAuth sign-in process with the specified provider.

Parameters

**provider** `string`

The OAuth provider type.

Returns

`Promise<void>`

Signature

```typescript theme={null}
declare function signInWithOAuth(provider: string): Promise<void>;
```

Examples

```typescript theme={null}
await hexclaveClientApp.signInWithOAuth("google");
```

### `hexclaveClientApp.signInWithCredential([options])`

Sign in using email and password credentials.

Parameters

**options.email** `string`

User's email.

**options.password** `string`

User's password.

**options.noRedirect** `boolean`

Whether to skip redirect after sign-in.

Returns

`Promise<Result<undefined, KnownErrors["EmailPasswordMismatch"]>>`

Signature

```typescript theme={null}
declare function signInWithCredential(options?: {
  email?: string;
  password?: string;
  noRedirect?: boolean;
}): Promise<Result<undefined, KnownErrors["EmailPasswordMismatch"]>>;
```

Examples

```typescript theme={null}
const result = await hexclaveClientApp.signInWithCredential({
  email: "test@example.com",
  password: "password",
});

if (result.status === "error") {
  console.error("Sign in failed", result.error.message);
}
```

### `hexclaveClientApp.signUpWithCredential([options])`

Sign up using email and password credentials.

Parameters

**options.email** `string`

User's email.

**options.password** `string`

User's password.

**options.noRedirect** `boolean`

Whether to skip redirect after sign-up.

Returns

`Promise<Result<undefined, KnownErrors["UserWithEmailAlreadyExists"] | KnownErrors["PasswordRequirementsNotMet"]>>`

Signature

```typescript theme={null}
declare function signUpWithCredential(options?: {
  email?: string;
  password?: string;
  noRedirect?: boolean;
}): Promise<Result<
  undefined,
  KnownErrors["UserWithEmailAlreadyExists"] | KnownErrors["PasswordRequirementsNotMet"]
>>;
```

Examples

```typescript theme={null}
const result = await hexclaveClientApp.signUpWithCredential({
  email: "test@example.com",
  password: "password",
});

if (result.status === "error") {
  console.error("Sign up failed", result.error.message);
}
```

### `hexclaveClientApp.sendForgotPasswordEmail(email)`

Send a forgot-password email to an email address.

Parameters

**email** `string`

The email to send the forgot-password email to.

Returns

`Promise<Result<undefined, KnownErrors["UserNotFound"]>>`

Signature

```typescript theme={null}
declare function sendForgotPasswordEmail(
  email: string,
): Promise<Result<undefined, KnownErrors["UserNotFound"]>>;
```

Examples

```typescript theme={null}
const result = await hexclaveClientApp.sendForgotPasswordEmail("test@example.com");

if (result.status === "success") {
  console.log("Forgot password email sent");
} else {
  console.error("Failed to send forgot password email", result.error.message);
}
```

### `hexclaveClientApp.sendMagicLinkEmail(email)`

Send a magic-link or OTP sign-in email to an email address.

Parameters

**email** `string`

The email to send the magic link to.

Returns

`Promise<Result<{ nonce: string }, KnownErrors["RedirectUrlNotWhitelisted"]>>`

Signature

```typescript theme={null}
declare function sendMagicLinkEmail(
  email: string,
): Promise<Result<{ nonce: string }, KnownErrors["RedirectUrlNotWhitelisted"]>>;
```

Examples

```typescript theme={null}
const result = await hexclaveClientApp.sendMagicLinkEmail("test@example.com");
```

## Analytics

### `hexclaveClientApp.initAnalytics()`

Marks the current page as one that should record [analytics](https://docs.hexclave.com/guides/apps/analytics/overview.md), including page views, clicks, session replays, and clickmaps.

Call this at the top level of a client-side module that every page you want to track loads, such as your root layout or entry file. Analytics capture starts as soon as the client app is created in the browser, so the function doesn't start anything itself. The call makes sure that the module creating the client app is loaded on every page, not just on pages that use authentication. See [Tracking every page](https://docs.hexclave.com/guides/apps/analytics/overview.md#tracking-every-page).

Throws if the app is configured so that it never records analytics (`analytics: { enabled: false }`, `automaticSideEffects: false`, or a `null` token store). If the Analytics app is not enabled on the project, an error is logged as soon as the first upload is rejected.

Returns

`void`

Signature

```typescript theme={null}
declare function initAnalytics(): void;
```

Examples

```typescript theme={null}
import { hexclaveClientApp } from "./hexclave/client";

hexclaveClientApp.initAnalytics();
```

***

# HexclaveServerApp

Like `HexclaveClientApp`, but with server permissions. Has full read and write access to all users.

> [!WARNING]
>
> Since this functionality should only be available in environments you trust
> (ie. your own server), it requires a `HEXCLAVE_SECRET_SERVER_KEY`. In some cases, you
> may want to use a `HexclaveServerApp` on the client; an example for this is an
> internal dashboard that only your own employees have access to. We generally
> recommend against doing this unless you are aware of and protected against the
> (potentially severe) security implications of exposing `HEXCLAVE_SECRET_SERVER_KEY` on
> the client.

## Table of Contents

```typescript theme={null}
type HexclaveServerApp =
  // Inherits all functionality from HexclaveClientApp
  & HexclaveClientApp
  & {
    new(options): HexclaveServerApp;

    getUser([id][, options]): Promise<ServerUser | null>;
    useUser([id][, options]): ServerUser;
    listUsers([options]): Promise<ServerUser[] & { nextCursor: string | null }>;
    useUsers([options]): ServerUser[] & { nextCursor: string | null };
    createUser([options]): Promise<ServerUser>;
    sendEmail(options): Promise<Result<void, KnownErrors>>;

    getTeam(id): Promise<ServerTeam | null>;
    useTeam(id): ServerTeam;
    listTeams([options]): Promise<ServerTeam[] & { nextCursor: string | null }>;
    useTeams([options]): ServerTeam[] & { nextCursor: string | null };
    createTeam([options]): Promise<ServerTeam>;
  }
```

## Constructor

Creates a new `HexclaveServerApp` instance.

Parameters

**tokenStore** `"nextjs-cookie" | "cookie" | \{ accessToken, refreshToken \} | Request` *required*

Token storage configuration.

**baseUrl** `string`

Base URL for the Hexclave API.

**projectId** `string`

Project ID.

**publishableClientKey** `string`

Publishable client key.

**secretServerKey** `string`

Secret server key. Defaults to the `HEXCLAVE_SECRET_SERVER_KEY` environment variable.

**urls** `object`

Redirect URL configuration.

**noAutomaticPrefetch** `boolean`

Disable automatic prefetching.

**automaticSideEffects** `boolean`

Whether inherited client-side constructor integrations run automatically. Defaults to `true`. Explicit method calls still work normally when set to `false`.

Signature

```typescript theme={null}
declare class HexclaveServerApp {
  constructor(options: {
    tokenStore: "nextjs-cookie" | "cookie" | {
      accessToken: string;
      refreshToken: string;
    } | Request;
    baseUrl?: string;
    projectId?: string;
    publishableClientKey?: string;
    secretServerKey?: string;
    urls?: object;
    noAutomaticPrefetch?: boolean;
    automaticSideEffects?: boolean;
  });
}
```

Examples

```typescript theme={null}
const hexclaveServerApp = new HexclaveServerApp({
  tokenStore: "nextjs-cookie",
  urls: {
    signIn: "/my-custom-sign-in-page",
  },
});
```

## User Operations

### `hexclaveServerApp.getUser([id], [options])`

Enhanced version of `HexclaveClientApp.getUser()` with server permissions.

**Overloads:**

1. `getUser(id: string): Promise<ServerUser | null>` to get a user by ID.
2. `getUser(options?: { or?: "return-null" | "redirect" | "throw" }): Promise<CurrentServerUser | null>` to get the current user.

> [!WARNING]
>
> The `or: "redirect"` overload is deprecated on both client and server app objects. The app
> type controls permissions, not whether the call runs in a browser. Use `getUser()` or
> `{ or: "throw" }` for server-side authorization, and `useUser({ or: "redirect" })` in a
> Client Component for navigation.

Signature

```typescript theme={null}
declare function getUser(id: string): Promise<ServerUser | null>;
declare function getUser(options?: {
  or?: "return-null" | "redirect" | "throw";
}): Promise<CurrentServerUser | null>;
```

Examples

```typescript theme={null}
const currentUser = await hexclaveServerApp.getUser();
console.log(currentUser);

const serverUser = await hexclaveServerApp.getUser(
  "12345678-1234-1234-1234-123456789abc",
);
console.log(serverUser);
```

### `hexclaveServerApp.useUser([id], [options])`

Functionally equivalent to [`getUser()`](#stackserverappgetuserid-options), but as a React hook.

> [!NOTE]
>
> This should be used on the server-side only.

Signature

```typescript theme={null}
declare function useUser(
  idOrOptions?: string | { or?: "return-null" | "redirect" | "throw" },
  options?: { or?: "return-null" | "redirect" | "throw" },
): ServerUser | CurrentServerUser | null;
```

### `hexclaveServerApp.listUsers([options])`

Lists all users on the project.

Parameters

**options.cursor** `string`

The cursor to start the result set from.

**options.limit** `number`

Maximum number of items to return per page, up to 1000. For larger result sets, pass `limit` and paginate with `cursor`. If omitted, projects with more than 1000 users return an error requiring pagination.

**options.orderBy** `"signedUpAt"`

The field to sort results by.

**options.desc** `boolean`

Whether to sort in descending order. Defaults to `false`.

**options.query** `string`

Free-text search on the user's display name and emails.

Returns

`Promise<ServerUser[] & { nextCursor: string | null }>`

Signature

```typescript theme={null}
declare function listUsers(options?: {
  cursor?: string;
  limit?: number;
  orderBy?: "signedUpAt";
  desc?: boolean;
  query?: string;
}): Promise<ServerUser[] & { nextCursor: string | null }>;
```

Examples

```typescript theme={null}
const users = await hexclaveServerApp.listUsers({ limit: 20 });
console.log(users);

if (users.nextCursor) {
  const nextPageUsers = await hexclaveServerApp.listUsers({
    cursor: users.nextCursor,
    limit: 20,
  });
  console.log(nextPageUsers);
}
```

### `hexclaveServerApp.useUsers([options])`

Functionally equivalent to [`listUsers()`](#stackserverapplistusersoptions), but as a React hook.

> [!NOTE]
>
> This should be used on the server-side only.

Signature

```typescript theme={null}
declare function useUsers(options?: {
  cursor?: string;
  limit?: number;
  orderBy?: "signedUpAt";
  desc?: boolean;
  query?: string;
}): ServerUser[] & { nextCursor: string | null };
```

### `hexclaveServerApp.createUser([options])`

Creates a new user from the server.

Parameters

**options.primaryEmail** `string`

User's primary email.

**options.primaryEmailVerified** `boolean`

Whether the email is verified.

**options.primaryEmailAuthEnabled** `boolean`

Whether email auth is enabled.

**options.password** `string`

User's password.

**options.otpAuthEnabled** `boolean`

Enable OTP or magic-link auth.

**options.displayName** `string`

User's display name.

Returns

`Promise<ServerUser>`

Signature

```typescript theme={null}
declare function createUser(options?: {
  primaryEmail?: string;
  primaryEmailVerified?: boolean;
  primaryEmailAuthEnabled?: boolean;
  password?: string;
  otpAuthEnabled?: boolean;
  displayName?: string;
}): Promise<ServerUser>;
```

Examples

```typescript theme={null}
const passwordUser = await hexclaveServerApp.createUser({
  primaryEmail: "test@example.com",
  primaryEmailAuthEnabled: true,
  password: "password123",
});

const magicLinkUser = await hexclaveServerApp.createUser({
  primaryEmail: "test@example.com",
  primaryEmailVerified: true,
  primaryEmailAuthEnabled: true,
  otpAuthEnabled: true,
});
```

### `hexclaveServerApp.sendEmail(options)`

Send custom emails to users. You can send either custom HTML emails or use predefined templates with variables.

Parameters

**options** `SendEmailOptions`

Email configuration and content.

Returns

`Promise<Result<void, KnownErrors>>`

The method returns a `Result` that can include `RequiresCustomEmailServer`, `SchemaError`, and `UserIdDoesNotExist`.

Signature

```typescript theme={null}
declare function sendEmail(
  options: SendEmailOptions,
): Promise<Result<void, KnownErrors>>;
```

Examples

```typescript theme={null}
const htmlResult = await hexclaveServerApp.sendEmail({
  userIds: ["user-1", "user-2"],
  subject: "Welcome to our platform!",
  html: "<h1>Welcome!</h1><p>Thanks for joining us.</p>",
});

if (htmlResult.status === "error") {
  console.error("Failed to send email:", htmlResult.error);
}
```

```typescript theme={null}
const templateResult = await hexclaveServerApp.sendEmail({
  userIds: ["user-1"],
  templateId: "welcome-template",
  variables: {
    userName: "John Doe",
    activationUrl: "https://app.com/activate/token123",
  },
});
```

## Team Management

### `hexclaveServerApp.getTeam(id)`

Get a team by its ID.

Parameters

**id** `string`

Team ID.

Returns

`Promise<ServerTeam | null>`

Signature

```typescript theme={null}
declare function getTeam(id: string): Promise<ServerTeam | null>;
```

Examples

```typescript theme={null}
const team = await hexclaveServerApp.getTeam("team_id_123");
```

### `hexclaveServerApp.useTeam(id)`

Functionally equivalent to [`getTeam(id)`](#stackserverappgetteamid), but as a React hook.

> [!NOTE]
>
> This should be used on the server-side only.

Signature

```typescript theme={null}
declare function useTeam(id: string): ServerTeam;
```

### `hexclaveServerApp.listTeams([options])`

Lists the teams on the current project.

Parameters

**options.cursor** `string`

The cursor to start the result set from. Requires `limit` to also be set.

**options.limit** `number`

Maximum number of items to return per page, up to 200. If omitted, all teams are returned, but the request fails if more than 500 teams match, so prefer setting `limit`. When there are more teams than `limit`, `nextCursor` is set and can be passed as `cursor` (together with `limit`) to fetch the rest.

**options.orderBy** `"createdAt"`

The field to sort results by.

**options.desc** `boolean`

Whether to sort in descending order. Defaults to `false`.

**options.query** `string`

Free-text search on the team's display name (and team ID if the query is a UUID).

Returns

`Promise<ServerTeam[] & { nextCursor: string | null }>`

Signature

```typescript theme={null}
declare function listTeams(options?: {
  cursor?: string;
  limit?: number;
  orderBy?: "createdAt";
  desc?: boolean;
  query?: string;
}): Promise<ServerTeam[] & { nextCursor: string | null }>;
```

Examples

```typescript theme={null}
const teams = await hexclaveServerApp.listTeams({ limit: 20 });
console.log(teams);

if (teams.nextCursor) {
  const nextPageTeams = await hexclaveServerApp.listTeams({
    cursor: teams.nextCursor,
    limit: 20,
  });
  console.log(nextPageTeams);
}
```

### `hexclaveServerApp.useTeams([options])`

Functionally equivalent to [`listTeams()`](#stackserverapplistteamsoptions), but as a React hook.

> [!NOTE]
>
> This should be used on the server-side only.

Signature

```typescript theme={null}
declare function useTeams(options?: {
  cursor?: string;
  limit?: number;
  orderBy?: "createdAt";
  desc?: boolean;
  query?: string;
}): ServerTeam[] & { nextCursor: string | null };
```

### `hexclaveServerApp.createTeam([options])`

Creates a team without adding a user to it.

Parameters

**options.displayName** `string`

Team display name.

**options.profileImageUrl** `string | null`

Team profile image URL.

Returns

`Promise<ServerTeam>`

Signature

```typescript theme={null}
declare function createTeam(options?: {
  displayName?: string;
  profileImageUrl?: string | null;
}): Promise<ServerTeam>;
```

Examples

```typescript theme={null}
const team = await hexclaveServerApp.createTeam({
  displayName: "New Team",
  profileImageUrl: "https://example.com/profile.jpg",
});
```
