> ## 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 Key Methods

> API reference for session key management - create, register, execute, query, and revoke delegated access

> [!WARNING]
>
> **PIN is weak — not recommended for production.**
>
> A user-typed PIN is a short, low-entropy string. Anyone who shoulder-surfs the PIN, observes a phishing form, or compromises the browser at typing time can decrypt the wallet's private key. PIN remains in the SDK only as a fallback recovery surface for users who lose access to their platform authenticator.
>
> **Production embedded-wallet apps should default to a platform passkey** (Touch ID, Face ID, Windows Hello, Android biometrics) via the `@chipi-stack/chipi-passkey` package. For SHHH V8.4 wallets, `signerKind: "WEBAUTHN_P256"` keeps the private key inside the platform authenticator — it never leaves the device, never reaches Chipi servers, and is never derived from a user-typed secret.
>
> Only prompt for a PIN as the encryption key when:
>
> * The user explicitly opted into a PIN-only flow (e.g. cold-storage / paper-backup recovery), or
> * The platform genuinely has no WebAuthn / biometric support available.
>
> If you are migrating an existing PIN-based wallet to a passkey, look up `useMigrateWalletToPasskey` in your framework's hook docs.

Session keys enable temporary, delegated transaction execution for [CHIPI wallets](https://github.com/chipi-pay/sessions-smart-contract) and SHHH V8.4 wallets, which embed the same sessions component. This page documents all available session methods.

***

## sessions.createSessionKey()

Generate a session keypair locally. The SDK returns the data but does NOT store it.

### Usage

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

### 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

Returns a `SessionKeyData` object:

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

### Example

```typescript theme={null}
// Create a 1-hour gaming session
const session = sdk.sessions.createSessionKey({
  encryptKey: userPin,
  durationSeconds: 60 * 60, // 1 hour
});

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

console.log(`Session expires at: ${new Date(session.validUntil * 1000)}`);
```

> [!WARNING]
>
> Store session data only in client-side secure storage (localStorage, Secure Enclave, Keychain). Never in your backend database.

***

## sessions.addSessionKeyToContract()

Register a session key on the [CHIPI wallet](https://github.com/chipi-pay/sessions-smart-contract) smart contract. Requires owner signature.

### Usage

```typescript theme={null}
const txHash = await sdk.sessions.addSessionKeyToContract({
  encryptKey: "user-secure-pin",
  wallet: {
    publicKey: "0x...",
    encryptedPrivateKey: "...",
    walletType: "CHIPI",
  },
  sessionConfig: {
    sessionPublicKey: session.publicKey,
    validUntil: session.validUntil,
    maxCalls: 100,
    allowedEntrypoints: [],
  },
}, bearerToken);
```

### Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `encryptKey` | string | Yes | PIN to decrypt owner's private key |
| `wallet` | WalletData | Yes | User's wallet data with `walletType: "CHIPI"` |
| `sessionConfig.sessionPublicKey` | string | Yes | Public key from `createSessionKey()` |
| `sessionConfig.validUntil` | number | Yes | Unix timestamp when session expires |
| `sessionConfig.maxCalls` | number | Yes | Maximum transactions allowed |
| `sessionConfig.allowedEntrypoints` | string\[] | Yes | Function names (`"transfer"`) or hex selectors. Names are converted to selectors (14.13.1+). A selector is allowed on every contract, not just one. Empty = all allowed |
| `bearerToken` | string | Yes | Valid JWT from your auth provider |

### Return Value

Returns a `Promise<string>` with the transaction hash.

### Example

```typescript theme={null}
// Register session with restricted permissions
const txHash = await sdk.sessions.addSessionKeyToContract({
  encryptKey: userPin,
  wallet: {
    publicKey: wallet.publicKey,
    encryptedPrivateKey: wallet.encryptedPrivateKey,
    walletType: "CHIPI",
  },
  sessionConfig: {
    sessionPublicKey: session.publicKey,
    validUntil: session.validUntil,
    maxCalls: 50,
    allowedEntrypoints: [
      "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", // transfer
    ],
  },
}, bearerToken);

console.log(`Session registered: https://starkscan.co/tx/${txHash}`);
```

> [!NOTE]
>
> This uses gasless transactions via the Chipi paymaster. Users don't need STRK for gas.

***

## sessions.setupSession() (14.14.0+)

Register a session **and** its spending policies in one owner-signed transaction. Equivalent to `addSessionKeyToContract` followed by one `setSpendingPolicy` per token, but the owner signs once and the session never exists on-chain without its caps.

### Usage

```typescript theme={null}
const txHash = await sdk.sessions.setupSession(
  {
    encryptKey,
    wallet,
    sessionConfig: {
      sessionPublicKey: session.publicKey,
      validUntil: session.validUntil,
      maxCalls: 500,
      allowedEntrypoints: ["transfer", "approve"],
    },
    spendingPolicies: [
      { token: USDC, maxPerCall: 5_000_000n, maxPerWindow: 20_000_000n, windowSeconds: 86_400 },
    ],
  },
  bearerToken
);
```

### Parameters

| Parameter | Type | Description |
| - | - | - |
| `encryptKey` | `string` | Decrypts the **owner** key |
| `wallet` | `WalletData` | CHIPI or SHHH wallet |
| `sessionConfig` | `SessionConfig` | Same as `addSessionKeyToContract` |
| `spendingPolicies` | `SessionSpendingPolicy[]` | Optional. One per token: `{ token, maxPerCall, maxPerWindow, windowSeconds }`. The session public key comes from `sessionConfig` |

Every call is built and validated before anything is signed: an invalid policy throws `INVALID_SPENDING_POLICY` and nothing is sent. `maxPerWindow: 0n` means no window cap.

### Call builders

The same calls are exported as pure functions, for batching with other calls or signing with your own owner path:

| Builder | Contract call |
| - | - |
| `buildAddSessionKeyCall(walletAddress, sessionConfig)` | `add_or_update_session_key` (names converted to selectors) |
| `buildSetSpendingPolicyCall(walletAddress, policy)` | `set_spending_policy` |
| `buildRemoveSpendingPolicyCall(walletAddress, sessionPublicKey, token)` | `remove_spending_policy` |
| `buildRevokeSessionKeyCall(walletAddress, sessionPublicKey)` | `revoke_session_key` |
| `buildSessionSetupCalls(walletAddress, sessionConfig, policies?)` | all of the above for a new session, in order |

All are imported from `@chipi-stack/backend`, together with `normalizeEntrypoints` and `validateSpendingPolicyConfig`.

***

## executeTransactionWithSession()

Execute a transaction using a session key instead of the owner's private key.

### Usage

```typescript theme={null}
const txHash = await sdk.executeTransactionWithSession({
  params: {
    encryptKey: "user-secure-pin",
    wallet: {
      publicKey: "0x...",
      encryptedPrivateKey: "...",
      walletType: "CHIPI",
    },
    session: {
      publicKey: "0x...",
      encryptedPrivateKey: "...",
      validUntil: 1702500000,
    },
    calls: [
      {
        contractAddress: "0x...",
        entrypoint: "transfer",
        calldata: ["0x...", "100", "0x0"],
      },
    ],
  },
  bearerToken,
});
```

### Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `params.encryptKey` | string | Yes | PIN to decrypt session private key |
| `params.wallet` | WalletData | Yes | User's wallet data |
| `params.session` | SessionKeyData | Yes | Session from `createSessionKey()` |
| `params.calls` | Call\[] | Yes | Array of contract calls to execute |
| `bearerToken` | string | No | JWT token (uses SDK default if not provided) |

### Return Value

Returns a `Promise<string>` with the transaction hash.

### Example

```typescript theme={null}
// Execute transfer using session (no owner key needed!)
const txHash = await sdk.executeTransactionWithSession({
  params: {
    encryptKey: userPin,
    wallet: { ...wallet, walletType: "CHIPI" },
    session,
    calls: [
      {
        contractAddress: USDC_CONTRACT,
        entrypoint: "transfer",
        calldata: [recipientAddress, amount, "0x0"],
      },
    ],
  },
  bearerToken,
});

console.log(`Transfer executed: https://starkscan.co/tx/${txHash}`);
```

> [!NOTE]
>
> **Signature Format:** Session transactions use a 4-element signature `[sessionPubKey, r, s, validUntil]` instead of the owner's 2-element `[r, s]`. The SDK handles this automatically.

***

## sessions.revokeSessionKey()

Remove a session key's authorization from the [CHIPI wallet](https://github.com/chipi-pay/sessions-smart-contract) contract.

### Usage

```typescript theme={null}
const txHash = await sdk.sessions.revokeSessionKey({
  encryptKey: "user-secure-pin",
  wallet: {
    publicKey: "0x...",
    encryptedPrivateKey: "...",
    walletType: "CHIPI",
  },
  sessionPublicKey: session.publicKey,
}, bearerToken);
```

### Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `encryptKey` | string | Yes | PIN to decrypt owner's private key |
| `wallet` | WalletData | Yes | User's wallet data with `walletType: "CHIPI"` |
| `sessionPublicKey` | string | Yes | Public key of session to revoke |
| `bearerToken` | string | Yes | Valid JWT from your auth provider |

### Return Value

Returns a `Promise<string>` with the transaction hash.

### Example

```typescript theme={null}
// Revoke session on logout
const handleLogout = async () => {
  const sessionStr = localStorage.getItem('chipiSession');
  
  if (sessionStr) {
    const session = JSON.parse(sessionStr);
    
    await sdk.sessions.revokeSessionKey({
      encryptKey: userPin,
      wallet: { ...wallet, walletType: "CHIPI" },
      sessionPublicKey: session.publicKey,
    }, bearerToken);
    
    localStorage.removeItem('chipiSession');
  }
  
  await authProvider.signOut();
};
```

> [!WARNING]
>
> Always revoke sessions on logout to prevent unauthorized access.

***

## sessions.getSessionData()

Query the on-chain status of a session key.

### Usage

```typescript theme={null}
const sessionData = await sdk.sessions.getSessionData({
  walletAddress: "0x...",
  sessionPublicKey: "0x...",
});
```

### Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `walletAddress` | string | Yes | The [CHIPI wallet](https://github.com/chipi-pay/sessions-smart-contract) address |
| `sessionPublicKey` | string | Yes | Public key of the session to query |

### Return Value

Returns a `Promise<SessionDataResponse>`:

```typescript theme={null}
{
  isActive: boolean;           // Registered, not expired, and has calls left
  validUntil: number;          // Unix timestamp of expiration; 0 = not registered or revoked
  remainingCalls: number;      // maxCalls minus calls already used
  allowedEntrypoints: string[]; // Always []: the contract returns only the whitelist length
}
```

### Example

```typescript theme={null}
// Check session before executing
const sessionData = await sdk.sessions.getSessionData({
  walletAddress: wallet.publicKey,
  sessionPublicKey: session.publicKey,
});

if (!sessionData.isActive) {
  console.log("Session expired or revoked - need to create new session");
  return;
}

if (sessionData.remainingCalls < 5) {
  console.log(`Warning: Only ${sessionData.remainingCalls} calls remaining`);
}

// Safe to proceed with transaction
await sdk.executeTransactionWithSession({ ... });
```

> [!TIP]
>
> Use `getSessionData()` to check remaining calls before batch operations.

***

## Error Handling

All session methods throw `ChipiSessionError` for session-specific failures:

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

try {
  await sdk.sessions.addSessionKeyToContract({ ... }, bearerToken);
} catch (error) {
  if (error instanceof ChipiSessionError) {
    switch (error.code) {
      case "INVALID_WALLET_TYPE_FOR_SESSION":
        console.error("Session keys only work with CHIPI wallets");
        break;
      case "SESSION_EXPIRED":
        console.error("Session has expired");
        break;
      case "SESSION_DECRYPTION_FAILED":
        console.error("Invalid PIN - could not decrypt session key");
        break;
      default:
        console.error("Session error:", error.message);
    }
  }
  throw error;
}
```

### Error Codes

| Code | Description |
| - | - |
| `INVALID_WALLET_TYPE_FOR_SESSION` | Wallet is not a [CHIPI wallet](https://github.com/chipi-pay/sessions-smart-contract) |
| `SESSION_EXPIRED` | Session `validUntil` has passed |
| `SESSION_NOT_REGISTERED` | Session not found on contract |
| `SESSION_REVOKED` | Session was explicitly revoked |
| `SESSION_MAX_CALLS_EXCEEDED` | No remaining calls |
| `SESSION_ENTRYPOINT_NOT_ALLOWED` | Called function not in whitelist |
| `SESSION_DECRYPTION_FAILED` | Invalid PIN for decryption |
| `SESSION_CREATION_FAILED` | Failed to generate keypair |

***

## Related

* [Session Keys Quickstart](/sdk/backend/sessions-quickstart) - Full lifecycle guide
* [CHIPI Wallet Smart Contract](https://github.com/chipi-pay/sessions-smart-contract) - Cairo implementation
* [Transfer](/sdk/backend/methods/transfer) - Basic token transfers
* [Call Any Contract](/sdk/backend/methods/call-any-contract) - Custom contract interactions


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.