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

# Session Keys

> Enable temporary, delegated transaction execution using the ChipiBrowserSDK. Session keys allow gasless, frictionless UX without requiring the owner private key for each transaction.

<Info>
  Session keys only work with **CHIPI wallets** - not READY wallets. Make sure your wallet was created with `walletType: "CHIPI"`.
</Info>

## Overview

Session keys allow your application to execute transactions on behalf of a user without requiring their owner private key for every action. This enables **gasless, frictionless UX** for gaming, DeFi automation, social apps, and more.

| Method                               | Description                        |
| ------------------------------------ | ---------------------------------- |
| `sessions.createSessionKey()`        | Generate a session keypair locally |
| `sessions.addSessionKeyToContract()` | Register session on-chain          |
| `sessions.revokeSessionKey()`        | Revoke a session key               |
| `sessions.getSessionData()`          | Query session status               |
| `executeTransactionWithSession()`    | Execute tx using session           |

***

## createSessionKey

Generate a session keypair locally. This is a **synchronous** operation that doesn't make network calls.

```typescript theme={null}
const session = browserClient.sessions.createSessionKey({
  encryptKey: "user-secure-pin",
  durationSeconds: 3600, // 1 hour (default: 6 hours)
});

console.log(session);
// {
//   publicKey: "0x...",
//   encryptedPrivateKey: "...",
//   validUntil: 1702500000
// }

// Store in client-side storage (NOT your database!)
localStorage.setItem('chipiSession', JSON.stringify(session));
```

### Parameters

| Parameter         | Type   | Required | Description                                            |
| ----------------- | ------ | -------- | ------------------------------------------------------ |
| `encryptKey`      | string | Yes      | PIN to encrypt the session private key                 |
| `durationSeconds` | number | No       | Session duration in seconds (default: 21600 = 6 hours) |

### Return Value

```typescript theme={null}
{
  publicKey: string;           // Session public key (hex)
  encryptedPrivateKey: string; // AES encrypted with encryptKey
  validUntil: number;          // Unix timestamp (seconds)
}
```

<Danger>
  **Never store session keys in your backend database.** Store only in client-side secure storage (localStorage, sessionStorage, or platform-specific secure storage).
</Danger>

***

## addSessionKeyToContract

Register a session key on the CHIPI wallet smart contract. This requires the owner's signature (one-time setup per session).

```typescript theme={null}
const bearerToken = await getBearerToken();

const txHash = await browserClient.sessions.addSessionKeyToContract({
  encryptKey: "user-secure-pin",
  wallet: {
    publicKey: wallet.publicKey,
    encryptedPrivateKey: wallet.encryptedPrivateKey,
    walletType: "CHIPI",
  },
  sessionConfig: {
    sessionPublicKey: session.publicKey,
    validUntil: session.validUntil,
    maxCalls: 100,           // Maximum transactions allowed
    allowedEntrypoints: [],  // Empty = all functions allowed
  },
}, bearerToken);

console.log("Session registered:", txHash);
```

### Parameters

| Parameter                          | Type       | Required | Description                                                         |
| ---------------------------------- | ---------- | -------- | ------------------------------------------------------------------- |
| `encryptKey`                       | string     | Yes      | Owner's PIN to sign the registration                                |
| `wallet`                           | WalletData | Yes      | Wallet object with `publicKey`, `encryptedPrivateKey`, `walletType` |
| `sessionConfig.sessionPublicKey`   | string     | Yes      | From `createSessionKey().publicKey`                                 |
| `sessionConfig.validUntil`         | number     | Yes      | Unix timestamp when session expires                                 |
| `sessionConfig.maxCalls`           | number     | Yes      | Maximum transactions allowed                                        |
| `sessionConfig.allowedEntrypoints` | string\[]  | Yes      | Whitelisted function selectors (empty = all)                        |

### Restricting Permissions

For enhanced security, whitelist specific function selectors:

```typescript theme={null}
const txHash = await browserClient.sessions.addSessionKeyToContract({
  encryptKey: pin,
  wallet: walletData,
  sessionConfig: {
    sessionPublicKey: session.publicKey,
    validUntil: session.validUntil,
    maxCalls: 10,
    allowedEntrypoints: [
      "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", // transfer
      "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", // approve
    ],
  },
}, bearerToken);
```

***

## revokeSessionKey

Revoke a session key from the smart contract. After revocation, the session can no longer execute transactions.

```typescript theme={null}
const bearerToken = await getBearerToken();

const txHash = await browserClient.sessions.revokeSessionKey({
  encryptKey: "user-secure-pin",
  wallet: {
    publicKey: wallet.publicKey,
    encryptedPrivateKey: wallet.encryptedPrivateKey,
    walletType: "CHIPI",
  },
  sessionPublicKey: session.publicKey,
}, bearerToken);

// Clear from local storage
localStorage.removeItem('chipiSession');

console.log("Session revoked:", txHash);
```

### Parameters

| Parameter          | Type       | Required | Description                        |
| ------------------ | ---------- | -------- | ---------------------------------- |
| `encryptKey`       | string     | Yes      | Owner's PIN to sign the revocation |
| `wallet`           | WalletData | Yes      | Wallet object                      |
| `sessionPublicKey` | string     | Yes      | Public key of session to revoke    |

<Warning>
  Always revoke sessions when a user logs out to prevent unauthorized access.
</Warning>

***

## getSessionData

Query session status from the smart contract. This is a **read-only** operation that doesn't require gas.

```typescript theme={null}
const sessionData = await browserClient.sessions.getSessionData({
  walletAddress: wallet.publicKey,
  sessionPublicKey: session.publicKey,
});

console.log(sessionData);
// {
//   isActive: true,
//   validUntil: 1702500000,
//   remainingCalls: 95,
//   allowedEntrypoints: []
// }

if (sessionData.isActive) {
  console.log(`Session has ${sessionData.remainingCalls} calls remaining`);
}
```

### Parameters

| Parameter          | Type   | Required | Description                 |
| ------------------ | ------ | -------- | --------------------------- |
| `walletAddress`    | string | Yes      | Wallet address to query     |
| `sessionPublicKey` | string | Yes      | Session public key to query |

### Return Value

```typescript theme={null}
{
  isActive: boolean;           // Whether session is valid
  validUntil: number;          // Expiration timestamp
  remainingCalls: number;      // Transactions remaining
  allowedEntrypoints: string[]; // Whitelisted functions
}
```

***

## executeTransactionWithSession

Execute a transaction using a session key instead of the owner private key. No wallet popup required!

```typescript theme={null}
const bearerToken = await getBearerToken();
const session = JSON.parse(localStorage.getItem('chipiSession')!);

const txHash = await browserClient.executeTransactionWithSession({
  params: {
    encryptKey: "user-secure-pin",
    wallet: {
      publicKey: wallet.publicKey,
      encryptedPrivateKey: wallet.encryptedPrivateKey,
      walletType: "CHIPI",
    },
    session,
    calls: [
      {
        contractAddress: "0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb",
        entrypoint: "transfer",
        calldata: [recipientAddress, amount, "0x0"],
      },
    ],
  },
  bearerToken,
});

console.log("Transaction executed:", txHash);
```

### Parameters

| Parameter           | Type           | Required | Description                                |
| ------------------- | -------------- | -------- | ------------------------------------------ |
| `params.encryptKey` | string         | Yes      | PIN to decrypt the **session** private key |
| `params.wallet`     | WalletData     | Yes      | Wallet the session acts on behalf of       |
| `params.session`    | SessionKeyData | Yes      | Session from `createSessionKey()`          |
| `params.calls`      | Call\[]        | Yes      | Array of contract calls                    |
| `bearerToken`       | string         | Yes      | Authentication token                       |

### Call Structure

```typescript theme={null}
{
  contractAddress: string;  // Target contract address
  entrypoint: string;       // Function name
  calldata: string[];       // Function arguments
}
```

### Multi-Call Example

Execute multiple operations in a single transaction:

```typescript theme={null}
const txHash = await browserClient.executeTransactionWithSession({
  params: {
    encryptKey: pin,
    wallet: walletData,
    session,
    calls: [
      // Approve spending
      {
        contractAddress: USDC_ADDRESS,
        entrypoint: "approve",
        calldata: [SWAP_CONTRACT, amount, "0x0"],
      },
      // Execute swap
      {
        contractAddress: SWAP_CONTRACT,
        entrypoint: "swap",
        calldata: [USDC_ADDRESS, ETH_ADDRESS, amount, minReceived],
      },
    ],
  },
  bearerToken,
});
```

***

## Complete Example: Gaming Session

```typescript theme={null}
import { ChipiBrowserSDK } from "@chipi-stack/backend";

const browserClient = new ChipiBrowserSDK({
  apiPublicKey: "pk_prod_your_public_key",
});

const GAME_CONTRACT = "0x...";
const MAKE_MOVE_SELECTOR = "0x...";

// Start a gaming session
async function startGameSession(userPin: string, bearerToken: string) {
  // Get player's wallet
  const wallet = await browserClient.getWallet({ externalUserId: "user-123" }, bearerToken);
  
  // Create 24-hour gaming session
  const session = browserClient.sessions.createSessionKey({
    encryptKey: userPin,
    durationSeconds: 24 * 60 * 60,
  });
  
  // Register with game-only permissions
  await browserClient.sessions.addSessionKeyToContract({
    encryptKey: userPin,
    wallet: { ...wallet, walletType: "CHIPI" },
    sessionConfig: {
      sessionPublicKey: session.publicKey,
      validUntil: session.validUntil,
      maxCalls: 1000,
      allowedEntrypoints: [MAKE_MOVE_SELECTOR],
    },
  }, bearerToken);
  
  // Store session
  localStorage.setItem('gameSession', JSON.stringify(session));
  
  return session;
}

// Make a move instantly - no wallet popup!
async function makeMove(moveData: string, userPin: string, bearerToken: string) {
  const session = JSON.parse(localStorage.getItem('gameSession')!);
  const wallet = await browserClient.getWallet({ externalUserId: "user-123" }, bearerToken);
  
  return browserClient.executeTransactionWithSession({
    params: {
      encryptKey: userPin,
      wallet: { ...wallet, walletType: "CHIPI" },
      session,
      calls: [{
        contractAddress: GAME_CONTRACT,
        entrypoint: "make_move",
        calldata: [moveData],
      }],
    },
    bearerToken,
  });
}

// Secure logout
async function logout(userPin: string, bearerToken: string) {
  const sessionStr = localStorage.getItem('gameSession');
  if (sessionStr) {
    const session = JSON.parse(sessionStr);
    const wallet = await browserClient.getWallet({ externalUserId: "user-123" }, bearerToken);
    
    try {
      await browserClient.sessions.revokeSessionKey({
        encryptKey: userPin,
        wallet: { ...wallet, walletType: "CHIPI" },
        sessionPublicKey: session.publicKey,
      }, bearerToken);
    } catch (e) {
      console.warn("Failed to revoke session:", e);
    }
    
    localStorage.removeItem('gameSession');
  }
}
```

***

## Error Handling

| Error                                    | Cause                    | Solution                                           |
| ---------------------------------------- | ------------------------ | -------------------------------------------------- |
| `Session keys require CHIPI wallet type` | Wallet is READY type     | Create wallet with `walletType: "CHIPI"`           |
| `Invalid encryptKey`                     | Wrong PIN                | Verify PIN matches wallet creation                 |
| `Session has expired`                    | `validUntil` passed      | Create and register a new session                  |
| `Max calls exceeded`                     | `remainingCalls` is 0    | Create new session with higher `maxCalls`          |
| `Entrypoint not allowed`                 | Function not whitelisted | Register session with correct `allowedEntrypoints` |

## Security Best Practices

1. **Short durations** - Use 1-6 hours, not days
2. **Limit calls** - Set realistic `maxCalls` based on expected usage
3. **Whitelist functions** - Restrict `allowedEntrypoints` to only what your app needs
4. **Revoke on logout** - Always clean up sessions when user signs out
5. **Client-side storage only** - Never store session keys in your database
