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

# TypeScript SDK

Typed clients for all Immutable APIs and services.

<Info>
  **Who is this for?** Web developers and TypeScript developers looking to build web3 applications and integrate blockchain features seamlessly.
</Info>

## Packages

Install only what you need:

| Package                   | Purpose                                | Install                         |
| ------------------------- | -------------------------------------- | ------------------------------- |
| `@imtbl/auth`             | Authentication & sessions              | `npm i @imtbl/auth`             |
| `@imtbl/wallet`           | Embedded wallets & transactions        | `npm i @imtbl/wallet`           |
| `@imtbl/auth-next-server` | Next.js server-side auth (Auth.js v5)  | `npm i @imtbl/auth-next-server` |
| `@imtbl/auth-next-client` | Next.js client-side hooks & components | `npm i @imtbl/auth-next-client` |
| `@imtbl/orderbook`        | NFT trading                            | `npm i @imtbl/orderbook`        |
| `@imtbl/blockchain-data`  | On-chain data queries (Indexer)        | `npm i @imtbl/blockchain-data`  |
| `@imtbl/minting-backend`  | Server-side minting                    | `npm i @imtbl/minting-backend`  |
| `@imtbl/contracts`        | Smart contract ABIs & types            | `npm i @imtbl/contracts`        |
| `@imtbl/webhook`          | Webhook signature validation           | `npm i @imtbl/webhook`          |
| `@imtbl/config`           | Environment configuration              | `npm i @imtbl/config`           |

<Info>
  Install individual packages instead of `@imtbl/sdk` for smaller bundles and better tree-shaking.
</Info>

## Installation

<Tabs>
  <Tab title="npm">
    ```bash theme={null}
    npm install @imtbl/sdk
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn add @imtbl/sdk
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add @imtbl/sdk
    ```
  </Tab>
</Tabs>

Or install individual packages for smaller bundles:

```bash theme={null}
npm install @imtbl/auth @imtbl/wallet @imtbl/config
```

## Framework Setup

<Tabs>
  <Tab title="Next.js (App Router)">
    Use `@imtbl/auth-next-server` and `@imtbl/auth-next-client` for full Next.js integration with server-side session management, automatic token refresh, and route protection.

    <Info>
      These packages require Next.js 14+ with the App Router. For Pages Router or other React frameworks, use `@imtbl/auth` directly.
    </Info>

    ### Prerequisites

    * **Client ID** from your [Passport client in Hub](/docs/products/hub/passport-clients)
    * Next.js 14 or 15 with App Router
    * An `AUTH_SECRET` environment variable (any random string, minimum 32 characters)

    ### Installation

    ```bash theme={null}
    npm install @imtbl/auth-next-server @imtbl/auth-next-client next-auth@5
    ```

    ### Setup

    <Steps>
      <Step title="Create auth configuration">
        Create your auth configuration:

        ```typescript theme={null}
        // lib/auth.ts
        import { NextAuth, createAuthConfig } from "@imtbl/auth-next-server";

        export const { handlers, auth, signIn, signOut } = NextAuth({
          ...createAuthConfig({
            clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
            redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
          }),
          secret: process.env.AUTH_SECRET,
          trustHost: true,
        });
        ```

        Create the API route handler:

        ```typescript theme={null}
        // app/api/auth/[...nextauth]/route.ts
        import { handlers } from "@/lib/auth";

        export const { GET, POST } = handlers;
        ```

        Wrap your app with `SessionProvider`:

        ```tsx theme={null}
        // app/layout.tsx
        import { SessionProvider } from "next-auth/react";

        export default function RootLayout({ children }: { children: React.ReactNode }) {
          return (
            <html lang="en">
              <body>
                <SessionProvider>{children}</SessionProvider>
              </body>
            </html>
          );
        }
        ```

        Set environment variables:

        ```env theme={null}
        # .env.local
        NEXT_PUBLIC_IMMUTABLE_CLIENT_ID=your_client_id
        NEXT_PUBLIC_BASE_URL=http://localhost:3000
        AUTH_SECRET=your-secret-key-min-32-characters
        ```
      </Step>

      <Step title="Create a callback page">
        Handle the OAuth redirect after login.

        ```tsx theme={null}
        // app/callback/page.tsx
        'use client';

        import { CallbackPage, type ImmutableAuthConfig } from '@imtbl/auth-next-client';

        const config: ImmutableAuthConfig = {
          clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
          redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
          audience: 'platform_api',
          scope: 'openid profile email offline_access transact',
        };

        export default function Callback() {
          return (
            <CallbackPage
              config={config}
              loadingComponent={<p>Completing authentication...</p>}
            />
          );
        }
        ```
      </Step>

      <Step title="Set environment variables">
        ```env theme={null}
        # .env.local
        NEXT_PUBLIC_IMMUTABLE_CLIENT_ID=your_client_id
        NEXT_PUBLIC_BASE_URL=http://localhost:3000
        AUTH_SECRET=your-secret-key-min-32-characters
        ```
      </Step>
    </Steps>

    For login, logout, session management, and wallet operations using the client hooks, see the **Next.js** tabs on the [Authentication](/docs/products/passport/authentication) and [Wallet](/docs/products/passport/wallet) pages.
  </Tab>

  <Tab title="Vite">
    ```bash theme={null}
    npm install @imtbl/auth @imtbl/wallet
    ```

    ### Initialization

    ```typescript theme={null}
    // src/lib/immutable.ts
    import { Auth } from '@imtbl/auth';
    import { connectWallet, ZkEvmProvider } from '@imtbl/wallet';

    export const auth = new Auth({
      clientId: import.meta.env.VITE_CLIENT_ID,
      redirectUri: `${window.location.origin}/callback`,
      logoutRedirectUri: window.location.origin,
      audience: 'platform_api',
      scope: 'openid offline_access email transact',
    });

    let providerPromise: Promise<ZkEvmProvider> | null = null;

    export function getProvider() {
      if (!providerPromise) {
        providerPromise = connectWallet({ auth });
      }
      return providerPromise;
    }
    ```

    ### Environment Variables

    ```env theme={null}
    VITE_CLIENT_ID=your_client_id
    ```

    ### Vite Configuration (Required)

    <Warning>
      Vite requires Node.js polyfills for the SDK. Without this configuration, builds will fail.
    </Warning>

    ```bash theme={null}
    npm install --save-dev vite-plugin-node-polyfills
    ```

    ```typescript theme={null}
    // vite.config.ts
    import { defineConfig } from 'vite';
    import { nodePolyfills } from 'vite-plugin-node-polyfills';

    export default defineConfig({
      plugins: [
        nodePolyfills()
      ]
    });
    ```
  </Tab>

  <Tab title="wagmi Integration">
    Use Passport with wagmi for React hooks:

    ```bash theme={null}
    npm install wagmi @imtbl/auth @imtbl/wallet
    ```

    ### Configuration

    ```typescript theme={null}
    import { createConfig, http } from 'wagmi';
    import { immutableZkEvmTestnet } from 'wagmi/chains';
    import { injected } from 'wagmi/connectors';

    export const wagmiConfig = createConfig({
      chains: [immutableZkEvmTestnet],
      connectors: [injected()],
      transports: {
        [immutableZkEvmTestnet.id]: http(),
      },
    });
    ```

    ### Component Example

    ```tsx theme={null}
    import { useAccount, useConnect } from 'wagmi';

    function WalletButton() {
      const { address, isConnected } = useAccount();
      const { connect, connectors } = useConnect();

      if (isConnected) {
        return <span>{address?.slice(0, 8)}...</span>;
      }

      return (
        <button onClick={() => connect({ connector: connectors[0] })}>
          Connect
        </button>
      );
    }
    ```
  </Tab>
</Tabs>

## Next.js Configuration

### `createAuthConfig`

Creates an Auth.js v5 configuration object for Immutable authentication.

| Option                 | Type     | Required                   | Default                                          |
| ---------------------- | -------- | -------------------------- | ------------------------------------------------ |
| `clientId`             | `string` | Yes (when config provided) | Sandbox client ID                                |
| `redirectUri`          | `string` | Yes (when config provided) | `origin + '/callback'`                           |
| `audience`             | `string` | No                         | `"platform_api"`                                 |
| `scope`                | `string` | No                         | `"openid profile email offline_access transact"` |
| `authenticationDomain` | `string` | No                         | `"https://auth.immutable.com"`                   |

When called with no arguments, `createAuthConfig()` uses sandbox defaults for quick prototyping.

<Warning>
  Zero-config mode uses a shared public sandbox client ID. For production, always use your own client ID from [Immutable Hub](https://hub.immutable.com).
</Warning>

### Extending the configuration

You can spread the base config and add any Auth.js options. This is the pattern used in the Passport sample app to support multiple environments:

```typescript theme={null}
import { NextAuth, createAuthConfig } from "@imtbl/auth-next-server";

export const { handlers, auth, signIn, signOut } = NextAuth({
  ...createAuthConfig({
    clientId: process.env.NEXT_PUBLIC_IMMUTABLE_CLIENT_ID!,
    redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/callback`,
  }),
  secret: process.env.AUTH_SECRET,
  trustHost: true,
  basePath: "/api/auth",
});
```

## Next.js Server Utilities

Use these in Server Components and Server Actions to handle authentication on the server.

### `getAuthProps`

Pass authentication state to a Client Component when data fetching happens client-side.

```typescript theme={null}
// app/dashboard/page.tsx
import { auth } from "@/lib/auth";
import { getAuthProps } from "@imtbl/auth-next-server";
import { redirect } from "next/navigation";
import { DashboardClient } from "./DashboardClient";

export default async function DashboardPage() {
  const authProps = await getAuthProps(auth);

  if (authProps.authError) {
    redirect("/login");
  }

  return <DashboardClient {...authProps} />;
}
```

### `getAuthenticatedData`

Fetch data server-side for faster initial loads, with automatic client-side fallback when the token is expired.

```typescript theme={null}
// app/profile/page.tsx
import { auth } from "@/lib/auth";
import { getAuthenticatedData } from "@imtbl/auth-next-server";
import { redirect } from "next/navigation";

async function fetchProfile(accessToken: string) {
  const res = await fetch("https://api.immutable.com/v1/user/profile", {
    headers: { Authorization: `Bearer ${accessToken}` },
  });
  return res.json();
}

export default async function ProfilePage() {
  const result = await getAuthenticatedData(auth, fetchProfile);

  if (result.authError) redirect("/login");

  return <ProfileClient {...result} />;
}
```

### `createProtectedFetchers`

Define auth error handling once and reuse it across all protected pages.

```typescript theme={null}
// lib/protected.ts
import { auth } from "@/lib/auth";
import { createProtectedFetchers } from "@imtbl/auth-next-server";
import { redirect } from "next/navigation";

export const { getAuthProps, getData } = createProtectedFetchers(
  auth,
  (error) => redirect(`/login?error=${error}`),
);
```

```typescript theme={null}
// app/settings/page.tsx
import { getAuthProps } from "@/lib/protected";

export default async function SettingsPage() {
  const authProps = await getAuthProps();
  return <SettingsClient {...authProps} />;
}
```

### `getValidSession`

Get fine-grained control over different authentication states.

```typescript theme={null}
import { auth } from "@/lib/auth";
import { getValidSession } from "@imtbl/auth-next-server";

export default async function AccountPage() {
  const result = await getValidSession(auth);

  switch (result.status) {
    case "authenticated":
      return <FullAccountPage session={result.session} />;
    case "token_expired":
      return <AccountPageSkeleton session={result.session} />;
    case "unauthenticated":
      return <LoginPrompt />;
    case "error":
      return <AuthErrorPage error={result.error} />;
  }
}
```

## Next.js Route Protection

### Middleware

Protect entire sections of your app at the routing level before pages render. Use middleware when you have groups of pages that all require authentication (such as `/dashboard/*` or `/settings/*`) and you want to redirect unauthenticated users before any page code runs.

<Info>
  Do not use middleware for pages that show different content for authenticated vs unauthenticated users, or for public pages with optional authenticated features. Use page-level checks with `getAuthProps` or `getValidSession` instead.
</Info>

```typescript theme={null}
// middleware.ts
import { createAuthMiddleware } from "@imtbl/auth-next-server";
import { auth } from "@/lib/auth";

export default createAuthMiddleware(auth, {
  loginUrl: "/login",
  publicPaths: ["/", "/about", "/api/public"],
});

export const config = {
  matcher: ["/((?!_next/static|_next/image|favicon.ico).*)"],
};
```

| Option           | Type                   | Description                                                     |
| ---------------- | ---------------------- | --------------------------------------------------------------- |
| `loginUrl`       | `string`               | Redirect target for unauthenticated users (default: `"/login"`) |
| `protectedPaths` | `(string \| RegExp)[]` | Paths that require authentication                               |
| `publicPaths`    | `(string \| RegExp)[]` | Paths that skip authentication (takes precedence)               |

### Protected API Routes

Use `withAuth` to protect individual Route Handlers or Server Actions.

```typescript theme={null}
// app/api/user/inventory/route.ts
import { auth } from "@/lib/auth";
import { withAuth } from "@imtbl/auth-next-server";
import { NextResponse } from "next/server";

export const GET = withAuth(auth, async (session, request) => {
  const inventory = await fetchUserInventory(session.accessToken);
  return NextResponse.json(inventory);
});
```

```typescript theme={null}
// app/actions/transfer.ts
"use server";

import { auth } from "@/lib/auth";
import { withAuth } from "@imtbl/auth-next-server";

export const transferAsset = withAuth(auth, async (session, formData: FormData) => {
  const assetId = formData.get("assetId") as string;
  const toAddress = formData.get("toAddress") as string;

  return await executeTransfer({
    from: session.user.sub,
    to: toAddress,
    assetId,
    accessToken: session.accessToken,
  });
});
```

<Info>
  Inside `withAuth` handlers, the `session` object includes `accessToken` directly since these run server-side. This is different from the client-side `useImmutableSession` hook where you must use `getAccessToken()`.
</Info>

## Next.js Session Type Reference

The server-side session (available in `withAuth` handlers and `getAuthenticatedData` fetchers) includes the following fields:

| Field                    | Type      | Description                               |
| ------------------------ | --------- | ----------------------------------------- |
| `user.sub`               | `string`  | Immutable user ID                         |
| `user.email`             | `string?` | User's email address                      |
| `user.nickname`          | `string?` | User's display name                       |
| `accessToken`            | `string`  | Current access token (server-side only)   |
| `refreshToken`           | `string?` | Refresh token                             |
| `accessTokenExpires`     | `number`  | Token expiry timestamp (ms)               |
| `zkEvm.ethAddress`       | `string?` | zkEVM wallet address                      |
| `zkEvm.userAdminAddress` | `string?` | Admin wallet address                      |
| `error`                  | `string?` | `"TokenExpired"` or `"RefreshTokenError"` |

<Warning>
  The client-side session from `useImmutableSession` intentionally omits `accessToken` to prevent use of stale tokens. Use `getAccessToken()` for API calls or `getUser()` for wallet integration.
</Warning>

<Info>
  The `idToken` is not stored in the session cookie to stay within CDN header size limits. On the client, `@imtbl/auth-next-client` persists it in `localStorage` so wallet operations can access it via `getUser()`.
</Info>

## Next.js Exported Utilities

The server package exports low-level utilities for manual token handling:

```typescript theme={null}
import {
  isTokenExpired,
  refreshAccessToken,
  extractZkEvmFromIdToken,
} from "@imtbl/auth-next-server";
```

| Utility                            | Description                                                          |
| ---------------------------------- | -------------------------------------------------------------------- |
| `isTokenExpired(expiresAt)`        | Check if an access token has expired                                 |
| `refreshAccessToken(token)`        | Manually refresh tokens using a refresh token                        |
| `extractZkEvmFromIdToken(idToken)` | Extract zkEVM claims (ethAddress, userAdminAddress) from an ID token |

## Environment Configuration

| Environment  | Chain             | API Base                    |
| ------------ | ----------------- | --------------------------- |
| `SANDBOX`    | Immutable Testnet | `api.sandbox.immutable.com` |
| `PRODUCTION` | Immutable Mainnet | `api.immutable.com`         |

## Next Steps

### Getting Started

<CardGroup cols={2}>
  <Card title="Configure Your Project" icon="gear" href="https://hub.immutable.com">
    Set up credentials and OAuth client in Immutable Hub
  </Card>

  <Card title="Authentication" icon="key" href="/docs/products/passport/authentication">
    Initialize Passport and implement login
  </Card>

  <Card title="Wallet Operations" icon="wallet" href="/docs/products/passport/wallet">
    Access wallet addresses and balances
  </Card>

  <Card title="Minting API" icon="coins" href="/docs/products/asset-contracts/minting-api">
    Server-side minting for NFTs at scale
  </Card>
</CardGroup>

### Additional Resources

<CardGroup cols={2}>
  <Card title="Architecture" icon="sitemap" href="/docs/products/passport/architecture">
    Understand the security model and smart contract wallets
  </Card>

  <Card title="FAQ" icon="circle-question" href="/docs/sdks/typescript/faq">
    Common questions and troubleshooting
  </Card>

  <Card title="GitHub" icon="github" href="https://github.com/immutable/ts-immutable-sdk">
    SDK source code
  </Card>

  <Card title="npm" icon="npm" href="https://www.npmjs.com/package/@imtbl/sdk">
    Package registry
  </Card>
</CardGroup>
