Account Sessions
Account sessions provide secure, scoped tokens for client-side embedded components. Sessions are tied to a specific account and can be restricted to specific components.
Create a Session
const session = await dialstack.accountSessions.create({
account: 'acct_01h2xcejqtf2nbrexx3vqjhp41',
components: {
call_logs: { enabled: true },
voicemails: { enabled: true },
},
});
console.log(session.client_secret); // 'cs_live_...'
console.log(session.expires_at); // '2025-01-15T13:00:00Z'
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
account | string | Yes | Account ID to scope the session to |
components | object | Yes | Component permissions. At least one component must be enabled — a missing, empty, or all-disabled set is rejected. |
Response
interface AccountSessionCreateResponse {
client_secret: string;
expires_at: string;
}
Component Permissions
Control which embedded components the session can access:
const session = await dialstack.accountSessions.create({
account: 'acct_01h2xcejqtf2nbrexx3vqjhp41',
components: {
call_logs: { enabled: true },
voicemails: { enabled: true },
},
});
Available Components
| Component | Description |
|---|---|
call_logs | Access to call history |
voicemails | Access to voicemails |
call_history | Access to the call-history component |
phone_numbers | Manage the account's phone numbers |
phone_number_ordering | Search for and order new phone numbers |
dial_plan | View and edit call routing |
ring_groups | Manage ring groups |
quality | Call-quality summary and worst calls |
ai_agent | Configure the AI agent |
account_onboarding | The onboarding portal, including reading the subscription agreement |
agreement_acceptance | Accepting the subscription agreement — see the warning below |
:::warning agreement_acceptance is an attestation
This component lets the session bind the account to the DialStack Service
Subscription Agreement — a legal commitment by your customer. It is separate from
account_onboarding on purpose: a session with onboarding alone can read the
agreement and render the accept screen, so someone who may not sign still learns
that service is blocked, but the submission is rejected.
DialStack does not decide who may sign, because the person is your user, not ours. You do, by enabling this component. By minting a session with it, you assert that you presented the agreement to someone entitled to accept on that account's behalf. Enable it for that person and leave it off for everyone else. DialStack's own admin portal, for reference, grants it only to the account's owner.
If you render the onboarding portal, pass
canAcceptAgreement with the same condition so a non-signer sees an explanation
instead of a button that fails.
:::
Restricting Access
// Only allow voicemails
const session = await dialstack.accountSessions.create({
account: accountId,
components: {
call_logs: { enabled: false },
voicemails: { enabled: true },
},
});
If a disabled component is used, it will show an error state.
Session Lifecycle
Expiration
Sessions expire after 1 hour by default. The expires_at field indicates when the session becomes invalid.
Client-Side Handling
Pass the full session response to enable automatic refresh:
// Server
app.post('/api/dialstack/session', async (req, res) => {
const session = await dialstack.accountSessions.create({
account: req.body.accountId,
components: {
call_logs: { enabled: true },
voicemails: { enabled: true },
},
});
// Return both fields
res.json({
client_secret: session.client_secret,
expires_at: session.expires_at,
});
});
// Client (React)
<DialstackComponentsProvider
dialstack={dialstack}
clientSecret={{
client_secret: session.client_secret,
expires_at: session.expires_at,
}}
>
Manual Refresh
If the session expires and you only passed the client_secret string:
// Client-side
async function refreshSession() {
const response = await fetch('/api/dialstack/session', {
method: 'POST',
body: JSON.stringify({ accountId }),
});
const session = await response.json();
setClientSecret(session.client_secret);
}
Security
API Key Required
Sessions can only be created with an API key (sk_live_*). This prevents clients from creating their own sessions.
// This works (server-side with API key)
const dialstack = new DialStack(process.env.DIALSTACK_API_KEY);
const session = await dialstack.accountSessions.create({
account: accountId,
components: { call_logs: { enabled: true } },
});
// Client-side tokens cannot create sessions
// (no accountSessions.create method available)
Account Isolation
Each session is scoped to a single account. The client_secret can only access data belonging to that account.
Token Security
- Tokens cannot be used to create new sessions
- Tokens are short-lived (1 hour)
- Tokens have limited scope (only enabled components)
Examples
Express.js Session Endpoint
import express from 'express';
import { DialStack } from '@dialstack/sdk-server';
const app = express();
const dialstack = new DialStack(process.env.DIALSTACK_API_KEY);
app.use(express.json());
app.post('/api/dialstack/session', async (req, res) => {
try {
const { accountId } = req.body;
// Verify user has access to this account
const userId = req.user?.id; // From auth middleware
const hasAccess = await verifyAccountAccess(userId, accountId);
if (!hasAccess) {
return res.status(403).json({ error: 'Access denied' });
}
// Create session
const session = await dialstack.accountSessions.create({
account: accountId,
components: {
call_logs: { enabled: true },
voicemails: { enabled: true },
},
});
res.json(session);
} catch (error) {
console.error('Session creation failed:', error);
res.status(500).json({ error: 'Failed to create session' });
}
});
Next.js API Route
// pages/api/dialstack/session.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { DialStack } from '@dialstack/sdk-server';
import { getServerSession } from 'next-auth';
const dialstack = new DialStack(process.env.DIALSTACK_API_KEY!);
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
// Check authentication
const authSession = await getServerSession(req, res);
if (!authSession) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { accountId } = req.body;
// Verify user owns this account
const userAccount = await db.accounts.findFirst({
where: {
dialstackAccountId: accountId,
userId: authSession.user.id,
},
});
if (!userAccount) {
return res.status(403).json({ error: 'Access denied' });
}
// Create session
const session = await dialstack.accountSessions.create({
account: accountId,
components: {
call_logs: { enabled: true },
voicemails: { enabled: true },
},
});
res.json(session);
}
Component-Specific Sessions
// Only voicemails for this user
async function getVoicemailSession(accountId: string) {
return dialstack.accountSessions.create({
account: accountId,
components: {
call_logs: { enabled: false },
voicemails: { enabled: true },
},
});
}
// Only call logs for analytics dashboard
async function getAnalyticsSession(accountId: string) {
return dialstack.accountSessions.create({
account: accountId,
components: {
call_logs: { enabled: true },
voicemails: { enabled: false },
},
});
}
Deprecated: sessions
The sessions property is deprecated. Use accountSessions instead:
const params = {
account: accountId,
components: { call_logs: { enabled: true } },
};
// Deprecated
const session = await dialstack.sessions.create(params);
// Use this instead
const session = await dialstack.accountSessions.create(params);
Next Steps
- Authentication - Full authentication flow
- React Components - Use sessions in React
- Web Components - Use sessions in vanilla JS