npm package: @kryptos_connect/web-sdk
Description: Kryptos simplifies Web3 finance for users globally with a comprehensive suite of solutions that include accounting, portfolio management, and tax reporting. Supporting over 2000+ DeFi protocols, 100+ exchanges and wallets, and 50+ blockchains, Kryptos is 
Author: Kryptos
Latest version: 2.0.1

# Kryptos Connect

A modern React component library for seamless Kryptos integration with built-in authentication, theme support, and wallet connectivity. Connect your users to the complete Web3 finance ecosystem with support for 5000+ DeFi protocols, 200+ exchanges and wallets, and 100+ blockchains.

## Installation

```bash
npm install @kryptos_connect/web-sdk
```

## Prerequisites

Before using this package, you'll need:

1. **Client ID**: Obtain from [Kryptos Developer Portal](https://dashboard.kryptos.io)
2. **WalletConnect Project ID**: Get from [WalletConnect Cloud](https://cloud.walletconnect.com)

## Quick Start

### Wrap Your App with Provider

Wrap your application with `KryptosConnectProvider`:

```tsx
import { KryptosConnectProvider } from "@kryptos_connect/web-sdk";

function App() {
  return (
    <KryptosConnectProvider
      config={{
        appName: "My DeFi App",
        appLogo: "https://yourapp.com/logo.png",
        clientId: "your-kryptos-client-id",
        theme: "light", // or "dark"
        walletConnectProjectId: "your-walletconnect-project-id",
      }}
    >
      {/* Your app components */}
    </KryptosConnectProvider>
  );
}
```

### Configuration Options

| Property                 | Type                        | Required | Description                                         |
| ------------------------ | --------------------------- | -------- | --------------------------------------------------- |
| `appName`                | `string`                    | Yes      | Your application name                               |
| `appLogo`                | `React.ReactNode \| string` | No       | Your app logo (URL string or React component)       |
| `clientId`               | `string`                    | Yes      | Your Kryptos client ID                              |
| `theme`                  | `"light" \| "dark"`         | No       | Default theme mode (defaults to "light" if not set) |
| `walletConnectProjectId` | `string`                    | Yes      | Your WalletConnect project ID                       |

## API Reference

### KryptosConnectButton

The main button component that triggers the Kryptos connection flow. It handles the full authentication and wallet connection process.

#### Basic Usage

```tsx
import { KryptosConnectButton } from "@kryptos_connect/web-sdk";

function MyComponent() {
  return (
    <KryptosConnectButton
      generateLinkToken={async () => {
        // Call your backend API to generate a link token
        const response = await fetch("/api/kryptos/create-link-token", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify({
            // Optional: Include access_token for authenticated users
            // access_token: userAccessToken
          }),
        });
        const data = await response.json();
        // Return link_token and isAuthorized flag
        return {
          link_token: data.link_token,
          isAuthorized: data.isAuthorized, // Pass true if access_token was provided
        };
      }}
      onConnectSuccess={(userConsent) => {
        console.log("Connection successful:", userConsent);
        // For new users, exchange the public token for an access token
        // For authorized users, userConsent might be null
        if (userConsent?.public_token) {
          exchangePublicToken(userConsent.public_token);
        }
      }}
      onConnectError={(error) => {
        console.error("Connection failed:", error);
      }}
    >
      Connect to Kryptos
    </KryptosConnectButton>
  );
}
```

#### User Flow Variations

The SDK automatically handles two different user flows based on the `isAuthorized` flag returned from `generateLinkToken`:

**Flow 1: New User** (`isAuthorized: false` or undefined)

```
INIT → Connect → INTEGRATION → STATUS
```

- User connects; an account is created for them on the backend
- User selects integrations to connect
- Returns `public_token` in `onConnectSuccess` callback

**Flow 2: Authenticated User** (`isAuthorized: true`)

```
INIT → INTEGRATION → STATUS
```

- Skips Connect (an account already exists for the user on the backend)
- User directly selects integrations
- Returns `null` in `onConnectSuccess` callback (no new token needed)

**Implementation Example:**

```tsx
generateLinkToken={async () => {
  const user = getCurrentUser(); // Your auth logic

  const response = await fetch("/api/kryptos/create-link-token", {
    method: "POST",
    body: JSON.stringify({
      // Include access_token if user is logged in
      access_token: user?.kryptosAccessToken || undefined,
    }),
  });

  const data = await response.json();

  return {
    link_token: data.link_token,
    // isAuthorized will be true if access_token was valid
    isAuthorized: !!user?.kryptosAccessToken,
  };
}}
```

#### Direct Integration Flow

You can use the `integrationName` prop to direct users to a specific integration, bypassing the general integration selection page. This is useful when you want to provide dedicated buttons for specific exchanges or wallets.

**Getting Supported Integration IDs:**

Fetch available integration IDs from the public Kryptos API endpoint:

```bash
GET {BASE_URL}/integrations/public/list
```

**Usage Example:**

```jsx
// Direct connection to a specific integration (e.g., Binance)
<KryptosConnectButton
  generateLinkToken={generateLinkToken}
  integrationName="binance"
  onConnectSuccess={(userConsent) => {
    console.log("Binance connected:", userConsent);
  }}
>
  Connect Binance Account
</KryptosConnectButton>

// Or without children (uses default button with custom text)
<KryptosConnectButton
  generateLinkToken={generateLinkToken}
  integrationName="metamask"
  onConnectSuccess={(userConsent) => {
    console.log("MetaMask connected:", userConsent);
  }}
  // Button will display: "Connect Metamask Account"
/>
```

**Use Cases:**

1. **Dedicated Integration Buttons**: Create separate buttons for popular integrations

   ```tsx
   <KryptosConnectButton integrationName="binance">
     Connect Binance
   </KryptosConnectButton>
   <KryptosConnectButton integrationName="coinbase">
     Connect Coinbase
   </KryptosConnectButton>
   <KryptosConnectButton integrationName="metamask">
     Connect MetaMask
   </KryptosConnectButton>
   ```

2. **Contextual Integration**: Direct users to relevant integrations based on their context

   ```tsx
   // In an exchange-focused feature
   <KryptosConnectButton integrationName="kraken">
     Add Kraken Account
   </KryptosConnectButton>
   ```

3. **Onboarding Flows**: Guide users to connect specific integrations during onboarding

   ```tsx
   // Step 1: Connect wallet
   <KryptosConnectButton integrationName="metamask">
     Connect Your Wallet
   </KryptosConnectButton>

   // Step 2: Connect exchange
   <KryptosConnectButton integrationName="binance">
     Connect Your Exchange
   </KryptosConnectButton>
   ```

**Note:** The `integrationName` value must match an integration ID from the supported providers list. An invalid ID will result in an error.

#### Custom Styling Example

```tsx
<KryptosConnectButton
  generateLinkToken={createLinkToken}
  onConnectSuccess={(userConsent) => {
    console.log("Success:", userConsent);
    exchangePublicToken(userConsent?.public_token);
  }}
  onConnectError={(error) => console.error("Error:", error)}
  className="my-custom-class"
  style={{
    width: "100%",
    padding: "12px 24px",
    fontSize: "16px",
  }}
>
  🔐 Connect Your Wallet
</KryptosConnectButton>
```

#### Props

| Property            | Type                                                            | Required | Description                                                                                                                                                            |
| ------------------- | --------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `generateLinkToken` | `() => Promise<{ link_token: string; isAuthorized?: boolean }>` | Yes      | Function that returns link token and authorization status. `isAuthorized: true` skips Connect for authenticated users (account already exists for them on the backend) |
| `onConnectSuccess`  | `(data: UserConsent \| null) => void`                           | No       | Callback invoked when connection succeeds. Receives `public_token` for new users, `null` for authorized users                                                          |
| `onConnectError`    | `(error: Error) => void`                                        | No       | Callback invoked when connection fails                                                                                                                                 |
| `integrationName`   | `string`                                                        | No       | Integration ID from the supported providers list. When provided, skips the integration list and goes directly to the specific integration                              |
| `children`          | `React.ReactNode`                                               | No       | Button text or content. Defaults to "Connect with Kryptos", or "Connect using {integrationName}" when `integrationName` is set                                         |
| `className`         | `string`                                                        | No       | Custom CSS class name                                                                                                                                                  |
| `style`             | `React.CSSProperties`                                           | No       | Inline styles                                                                                                                                                          |

#### TypeScript Types

```typescript
interface KryptosConnectButtonProps {
  generateLinkToken: () => Promise<{
    link_token: string;
    isAuthorized?: boolean;
  }>;
  onConnectSuccess?: (data: UserConsent | null) => void;
  onConnectError?: (error: Error) => void;
  integrationName?: string; // Integration ID from the supported providers list
  children?: React.ReactNode;
  className?: string;
  style?: React.CSSProperties;
}

interface UserConsent {
  public_token: string;
  // Additional consent data
}

// Note: onConnectSuccess receives:
// - UserConsent with public_token for new users (isAuthorized: false)
// - null for authenticated users (isAuthorized: true)
```

### Backend Integration

You need to implement two backend endpoints.

#### Base URLs

| Environment    | URL                              |
| -------------- | -------------------------------- |
| **Production** | `https://connect-api.kryptos.io` |

#### 1. Create Link Token

A link token can be created in two ways: to authenticate an existing user or to create a new session.

| Approach                  | When to use                      | Jump to                                  |
| ------------------------- | -------------------------------- | ---------------------------------------- |
| **[Option A](#option-a)** | New user, no access token        | Create link token without `access_token` |
| **[Option B](#option-b)** | Returning user, has access token | Create link token with `access_token`    |

<a id="option-a"></a>

##### Option A: Without Access Token (New User)

Use this approach for **new users** or when you want an account to be created for the user on the backend:

```javascript
// Example: Node.js/Express
app.post("/api/kryptos/create-link-token", async (req, res) => {
  try {
    const response = await fetch(`${KRYPTOS_BASE_URL}/link-token`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Client-Id": YOUR_CLIENT_ID,
        "X-Client-Secret": YOUR_CLIENT_SECRET,
      },
      body: JSON.stringify({
        scopes:
          "openid profile offline_access email portfolios:read transactions:read integrations:read tax:read accounting:read reports:read workspace:read users:read",
      }),
    });

    const data = await response.json();
    res.json({
      link_token: data.link_token,
      isAuthorized: false, // No access token provided
    });
  } catch (error) {
    res.status(500).json({ error: "Failed to create link token" });
  }
});
```

**User Experience Flow**:

1. User clicks "Connect to Kryptos"
2. User connects; an account is created for them on the backend
3. User selects integrations
4. `onConnectSuccess` receives `public_token` to exchange

<a id="option-b"></a>

##### Option B: With Access Token (Authenticated User)

Use this approach for **existing authenticated users** (an account already exists for them on the backend):

```javascript
// Example: Node.js/Express
app.post("/api/kryptos/create-link-token", async (req, res) => {
  try {
    // Get the user's stored access token from your database
    const userAccessToken = await getUserAccessToken(req.user.id);

    const response = await fetch(`${KRYPTOS_BASE_URL}/link-token`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Client-Id": YOUR_CLIENT_ID,
        "X-Client-Secret": YOUR_CLIENT_SECRET,
      },
      body: JSON.stringify({
        scopes:
          "openid profile offline_access integrations:read integrations:write",
        access_token: userAccessToken, // Pass the user's access token
      }),
    });

    const data = await response.json();
    res.json({
      link_token: data.link_token,
      isAuthorized: true, // Access token provided, user is authenticated
    });
  } catch (error) {
    res.status(500).json({ error: "Failed to create link token" });
  }
});
```

**User Experience Flow**:

1. User clicks "Connect to Kryptos"
2. Integration selection is shown directly (account already exists for the user on the backend)
3. User selects integrations
4. `onConnectSuccess` receives `null` (no new token needed)

##### Choosing the Right Approach

**Implementation:** [**Option A**](#option-a) (new user, no token) · [**Option B**](#option-b) (authenticated user, with token)

| Scenario                                   | Use Option                         | isAuthorized | User Flow (UI)                                              | Returns public_token |
| ------------------------------------------ | ---------------------------------- | ------------ | ----------------------------------------------------------- | -------------------- |
| First-time user connecting to Kryptos      | [**A**](#option-a) (Without Token) | `false`      | Connect → INTEGRATION (account created for user on backend) | ✅ Yes               |
| User doesn't have an access token yet      | [**A**](#option-a) (Without Token) | `false`      | Connect → INTEGRATION (account created for user on backend) | ✅ Yes               |
| Returning user with stored access token    | [**B**](#option-b) (With Token)    | `true`       | INTEGRATION only (account already exists for user)          | ❌ No                |
| Adding more integrations for existing user | [**B**](#option-b) (With Token)    | `true`       | INTEGRATION only (account already exists for user)          | ❌ No                |

**Important Notes**:

- After the first successful connection (Option A), store the `access_token` you receive from the token exchange
- Use the stored `access_token` for subsequent connections (Option B) to provide a seamless experience
- For authorized users (`isAuthorized: true`), the `onConnectSuccess` callback receives `null` instead of a `public_token`
- Authorized users go directly to integration selection (an account already exists for them on the backend)

#### 2. Exchange Public Token

After a successful connection, exchange the `public_token` for an `access_token`. **Important:** Store this `access_token` securely in your database. You will use it to create link tokens for authenticated users (Option B above).

```javascript
// Example: Node.js/Express
app.post("/api/kryptos/exchange-token", async (req, res) => {
  try {
    const { public_token } = req.body;

    const response = await fetch(`${KRYPTOS_BASE_URL}/token/exchange`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-Client-Id": YOUR_CLIENT_ID,
        "X-Client-Secret": YOUR_CLIENT_SECRET,
      },
      body: JSON.stringify({
        public_token,
      }),
    });

    const data = await response.json();

    // IMPORTANT: Store the access_token securely in your database
    // You'll need this token to:
    // 1. Create authenticated link tokens (account already exists for user on backend)
    // 2. Make API calls on behalf of the user
    await saveUserAccessToken(req.user.id, data.access_token);

    res.json({ success: true });
  } catch (error) {
    res.status(500).json({ error: "Failed to exchange token" });
  }
});
```

**Complete Integration Flow:**

1. **First Connection** (New User - `isAuthorized: false`):

   ```
   Frontend → generateLinkToken() [returns { link_token, isAuthorized: false }]
   → SDK Flow: INIT → Connect → INTEGRATION → STATUS
   → User connects; an account is created for them on the backend
   → User connects integrations
   → onConnectSuccess receives { public_token: "..." }
   → Backend exchanges public_token for access_token
   → Store access_token in database ← IMPORTANT
   ```

2. **Subsequent Connections** (Returning User - `isAuthorized: true`):
   ```
   Frontend → generateLinkToken() [returns { link_token, isAuthorized: true }]
   → SDK Flow: INIT → INTEGRATION → STATUS (skip Connect)
   → User directly sees integrations (account already exists for them on the backend)
   → User connects more integrations
   → onConnectSuccess receives null (no new token needed)
   → Integrations are added to user's existing account
   ```

## Customization

The library uses CSS variables and unique `kc-` prefixed classes for easy customization without conflicts.

See [CUSTOMIZATION_GUIDE.md](./CUSTOMIZATION_GUIDE.md) for detailed CSS customization options.

### Quick Theme Customization

Override CSS variables to customize the look and feel:

```css
/* custom-theme.css */
:root {
  --kc-primary: #8b5cf6;
  --kc-primary-hover: #7c3aed;
  --kc-bg-primary: #ffffff;
  --kc-text-primary: #000000;
  --kc-border: #e5e7eb;
  --kc-border-radius: 8px;
}

[data-kc-theme="dark"] {
  --kc-bg-primary: #1a1a1a;
  --kc-text-primary: #ffffff;
  --kc-border: #404040;
}
```

Import your custom styles after the package styles:

```tsx
import "./custom-theme.css";
```

### Custom Component Styling

```tsx
<KryptosConnectButton
  className="my-custom-button"
  style={{
    background: "linear-gradient(to right, #667eea, #764ba2)",
    borderRadius: "12px",
  }}
>
  Connect Wallet
</KryptosConnectButton>
```

## Framework Support

### Next.js

Works with both Pages Router and App Router:

```tsx
// app/layout.tsx (App Router)
import { KryptosConnectProvider } from "@kryptos_connect/web-sdk";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <KryptosConnectProvider config={config}>
          {children}
        </KryptosConnectProvider>
      </body>
    </html>
  );
}
```

### React

```tsx
// main.tsx or index.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import { KryptosConnectProvider } from "@kryptos_connect/web-sdk";
import App from "./App";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <KryptosConnectProvider config={config}>
      <App />
    </KryptosConnectProvider>
  </React.StrictMode>,
);
```

## TypeScript Support

This package provides full TypeScript support with type definitions.

```typescript
import type {
  KryptosConnectButtonProps,
  KryptosConnectProviderProps,
  UserConsent,
} from "@kryptos_connect/web-sdk";
```

## Browser Support

- Chrome/Edge (latest)
- Firefox (latest)
- Safari (latest)
- Mobile browsers (iOS Safari, Chrome Mobile)

## Support

- 📧 Email: [support@kryptos.io](mailto:support@kryptos.io)
- 📚 Documentation: [https://docs.kryptos.io](https://docs.kryptos.io)
- 💬 Discord: [Join our community](https://discord.gg/kryptos)
- 🐛 Issues: [GitHub Issues](https://github.com/kryptos/connect-npm-package/issues)

## Contributing

Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our code of conduct and the process for submitting pull requests.

## License

MIT © [Kryptos](https://kryptos.io)

---

Made with ❤️ by the Kryptos team