Authentication
Two types of keys for two different contexts. Use the right one for your use case.
Key Types
Publishable Key
pk_live_...Safe to use in browsers, mobile apps, and any client code. Can only create voice/chat sessions — nothing else. Cannot read agent configs, make outbound calls, or access any admin APIs.
Secret Key
sk_live_...Full account access. Manage agents, initiate calls, access recordings, generate tokens. NEVER use in client code — only in your backend (env vars, server SDK).
Client SDK — Publishable Key
The simplest way to integrate. Drop in your publishable key and agent ID — done. The key is safe to expose because it can only create sessions for agents YOU configured on the platform.
import { useConverseVoice, ConverseOrb } from '@converse/sdk/components';
function VoiceAgent() {
const { agentState, voiceState, connect, disconnect } = useConverseVoice({
publicKey: 'pk_live_abc123...', // Safe in client code
agentId: 'agent_xxx',
});
return (
<ConverseOrb
state={agentState}
size="lg"
onClick={voiceState === 'idle' ? connect : disconnect}
/>
);
}What can a publishable key do?
Client SDK — Token Provider
For extra control (e.g., you want to authenticate YOUR user before allowing a call), use a token provider. Your backend validates the user, then generates a short-lived session token.
Your backend
import { getVoiceToken } from '@converse/sdk/mobile';
app.post('/api/voice-token', async (req, res) => {
// Your auth: verify the user is logged in, has credits, etc.
if (!req.user) return res.status(401).json({ error: 'Unauthorized' });
const session = await getVoiceToken(req.body.agentId, {
apiKey: process.env.CONVERSE_API_KEY!,
allowedAgentIds: ['agent_xxx'],
});
res.json(session);
});Your client
const { connect } = useConverseVoice({
agentId: 'agent_xxx',
tokenProvider: async () => {
const res = await fetch('/api/voice-token', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer ' + userToken },
body: JSON.stringify({ agentId: 'agent_xxx' }),
});
return res.json();
},
});Server SDK — Secret Key
Your backend uses the secret key for full API access. Manage agents, calls, numbers, and contacts.
import { ConverseClient } from '@converse/sdk';
// Secret key in env var — never in client code
const converse = new ConverseClient({ apiKey: process.env.CONVERSE_API_KEY! });
const call = await converse.calls.create({ agent_id: 'agent_xxx', to: '+91...' });
const agents = await converse.agents.list();Security Summary
pk_live_...Where: Browser, mobile, client code
Can do: Create voice/chat sessions only
Risk: Low — someone could start calls to your agent
sk_live_...Where: Server ONLY (env vars)
Can do: Full account access
Risk: High — full control of your account
tokenProviderWhere: Client calls your backend
Can do: Whatever you authorize
Risk: None — you control access
