Sessions
Session tokens are the secure way to grant browser and mobile clients temporary, scoped access to the Burn & Claim API without exposing your API key.
How sessions work
- Your backend calls
createSession()with an API key, specifying the wallet address and desired scopes. - The API returns a signed JWT (the session token) bound to that wallet and those scopes.
- Your frontend constructs a
BurnerClientwith the session token and makes API calls directly. - When the token expires, the frontend requests a new one from your backend.
┌──────────┐ POST /sessions ┌──────────┐
│ Backend │ ──────────────────────> │ API │
│ (API key) │ <────────────────────── │ │
└──────────┘ { token, expiresAt } └──────────┘
│
│ forward token
v
┌──────────┐ GET /wallet/assets ┌──────────┐
│ Frontend │ ──────────────────────> │ API │
│ (session) │ <────────────────────── │ │
└──────────┘ { items, counts } └──────────┘Creating a session
import { BurnerClient, SessionScope } from '@burnandclaim/sdk'
const server = new BurnerClient({
apiKey: process.env.BURNER_API_KEY,
})
const session = await server.createSession({
walletAddress: 'DRpb...xy4Z',
scopes: [
SessionScope.WalletRead,
SessionScope.TransactionsBuild,
SessionScope.TransactionsSubmit,
],
ttlSeconds: 600,
})
// session.token → "eyJhbGci..."
// session.expiresAt → "2026-04-09T12:10:00.000Z"
// session.scopes → ["wallet:read", "transactions:build", "transactions:submit"]Scope reference
| Constant | Value | Grants access to |
|---|---|---|
SessionScope.WalletRead | wallet:read | GET /wallet/:address/assets |
SessionScope.WalletStream | wallet:stream | WebSocket streamWalletAssets |
SessionScope.TransactionsBuild | transactions:build | POST /wallet/:address/transactions |
SessionScope.TransactionsSubmit | transactions:submit | POST /wallet/:address/transactions/submit |
Default scopes
If you omit the scopes field, the session receives all four scopes:
import { SESSION_SCOPES_DEFAULT } from '@burnandclaim/sdk'
// ['wallet:read', 'wallet:stream', 'transactions:build', 'transactions:submit']Minimal scopes
Request only what you need. A read-only integration only needs:
scopes: [SessionScope.WalletRead]Token lifetime
| Parameter | Default | Maximum |
|---|---|---|
ttlSeconds | 300 (5 min) | 3600 (1 hr) |
Tokens cannot be refreshed or extended. When a token expires, create a new one.
Wallet binding
Each session token is bound to exactly one wallet address. Attempting to use a token created for wallet A to access wallet B’s assets returns 401 Unauthorized.
This means you need one session per wallet. If a user switches wallets in your UI, create a fresh session for the new address.
Handling expiry
When a session token expires, the API returns:
{
"statusCode": 401,
"message": "Session expired"
}Implement a recreate flow in your frontend:
class BurnService {
private client: BurnerClient | null = null
private walletAddress: string
constructor(walletAddress: string) {
this.walletAddress = walletAddress
}
private async ensureClient(): Promise<BurnerClient> {
if (!this.client) {
const res = await fetch('/api/burn-session', {
method: 'POST',
body: JSON.stringify({ walletAddress: this.walletAddress }),
headers: { 'Content-Type': 'application/json' },
})
const { token } = await res.json()
this.client = new BurnerClient({ sessionToken: token })
}
return this.client
}
async getAssets(): Promise<WalletAssets> {
try {
const client = await this.ensureClient()
return await client.getWalletAssets(this.walletAddress)
} catch (err: unknown) {
if (err instanceof Error && err.message.includes('401')) {
this.client = null // force recreate
const client = await this.ensureClient()
return await client.getWalletAssets(this.walletAddress)
}
throw err
}
}
}Last updated on