Quick Start — 5 Minutes to Session Keys
bashnpm install @sessionguard/sdk
# or
pnpm add @sessionguard/sdk
# or
yarn add @sessionguard/sdk
Sign up at sessionguard.io and get your API key:
sg_test_xxx for testnets (Sepolia, Base Goerli)sg_live_xxx for production (Ethereum, Polygon, Base, Arbitrum, Optimism)typescriptimport { SessionGuardClient } from '@sessionguard/sdk';
const client = new SessionGuardClient({
chainId: 8453, // Base
rpcUrl: 'https://mainnet.base.org',
bundlerUrl: 'https://bundler.sessionguard.io/base',
paymasterUrl: 'https://paymaster.sessionguard.io/base', // optional: sponsor gas
});
typescript// User connects their wallet (MetaMask, WalletConnect, etc.)
const userWallet = '0x...'; // from your wallet connection
// Deploy a smart account (idempotent — returns existing if already deployed)
const account = await client.createAccount({ owner: userWallet });
console.log('Smart Account:', account);
typescriptimport { AllowlistPolicy, SpendingLimitPolicy } from '@sessionguard/sdk';
// This is the ONE TIME the user's master key signs
const session = await client.createSession({
account,
label: 'My App Session',
ttlSeconds: 24 * 60 * 60, // 24 hours
policies: [
AllowlistPolicy({
rules: [
{ target: YOUR_CONTRACT, selector: '0x12345678' },
],
}),
SpendingLimitPolicy({ maxAmount: 1_000_000n }), // 1 USDC
],
});
typescript// This uses the session key — user is never prompted
const receipt = await client.execute({
session,
target: YOUR_CONTRACT,
data: '0x...', // encoded function call
});
console.log('Tx:', receipt.transactionHash);
| Chain | Chain ID | Status |
|---|---|---|
| Ethereum Mainnet | 1 | ✅ Production |
| Polygon | 137 | ✅ Production |
| Base | 8453 | ✅ Production |
| Arbitrum One | 42161 | ✅ Production |
| Optimism | 10 | ✅ Production |
| Sepolia (testnet) | 11155111 | ✅ Testing |
| Base Goerli (testnet) | 84531 | ✅ Testing |
Caps the total value a session key can spend.
typescriptSpendingLimitPolicy({
maxAmount: 10_000_000n, // in token's smallest unit (e.g., 10 USDC)
token: USDC_ADDRESS, // optional; omit for native ETH
})
Restricts which contracts and functions the session key can call.
typescriptAllowlistPolicy({
rules: [
{ target: CONTRACT_A, selector: '0x12345678' }, // specific function
{ target: CONTRACT_B, selector: '0xabcdef01' }, // another function
],
})
Sets session duration (alternative to ttlSeconds).
typescriptTimeBoundPolicy({ duration: '24h' }) // supports: 30s, 5m, 2h, 7d, 1w
Limits operations per time window.
typescriptRateLimitPolicy({
maxOps: 100, // max operations
windowSeconds: 3600, // per 1 hour
})
Caps total gas consumption.
typescriptGasLimitPolicy({ maxGas: 10_000_000n }) // 10M gas units total
If you prefer REST over the SDK:
httpPOST /api/v1/accounts
Authorization: Bearer sg_live_xxx
Content-Type: application/json
{
"ownerAddress": "0x...",
"chainId": 8453
}
httpPOST /api/v1/sessions
Authorization: Bearer sg_live_xxx
Content-Type: application/json
{
"account": "0x...",
"chainId": 8453,
"ttlSeconds": 86400,
"label": "Game Session",
"policies": [
{ "type": "spending-limit", "maxAmount": "1000000" },
{ "type": "allowlist", "rules": [{ "target": "0x...", "selector": "0x..." }] }
]
}
httpDELETE /api/v1/sessions/:account/:sessionKey
Authorization: Bearer sg_live_xxx
httpPOST /api/v1/bundler/send
Authorization: Bearer sg_live_xxx
Content-Type: application/json
{
"chainId": 8453,
"userOp": { ... }
}
typescripttry {
await client.execute({ session, target, data });
} catch (error) {
if (error.message.includes('SessionKeyExpired')) {
// Session expired — create a new one (user signs again)
session = await client.createSession({ ... });
} else if (error.message.includes('SpendingLimitExceeded')) {
// Budget exhausted
console.log('Session budget used up');
} else if (error.message.includes('PolicyCheckFailed')) {
// Tried to call a non-allowed function
console.log('Action not allowed by session policy');
}
}