SDK
The @ph0ny/sdk package provides a typed TypeScript/JavaScript client for the ph0ny Voice API.
Installation
bash
pnpm add @ph0ny/sdk
# or
npm install @ph0ny/sdkQuick Start
typescript
import { createVoiceClient } from '@ph0ny/sdk'
const client = createVoiceClient({
apiKey: 'plabs_your_key_here',
})Configuration
typescript
import { createVoiceClient } from '@ph0ny/sdk'
const client = createVoiceClient({
apiKey: 'plabs_...',
baseUrl: 'https://persona-labsvoice-api-production.up.railway.app/v1', // optional, defaults to production
timeout: 30000, // request timeout in ms
providerKeys: { // optional BYOK keys
elevenlabs: 'sk_...',
openai: 'sk-...',
cartesia: 'sk_...',
},
})Client Namespaces
The VoiceClient organizes methods into sub-clients:
| Namespace | Description |
|---|---|
client.agents | Agent CRUD, chat, speak, provision |
client.tts | Text-to-speech synthesis |
client.stt | Speech-to-text transcription |
client.rag | Collection management and search |
client.sessions | Twilio and WebSocket session creation |
client.tests | Agent test cases and self-play |
client.conversations | Conversation history |
client.observability | Session traces and quality metrics |
client.recordings | Call recording retrieval |
client.providerKeysClient | Stored provider key management |
client.onboarding | Onboarding interview flows |
client.tasks | Outbound call task dispatch |
Agents
typescript
// Create
const agent = await client.agents.create({
name: 'Support Agent',
systemPrompt: 'You are a customer support agent for Acme Corp.',
firstMessage: 'Hi, thanks for calling Acme. How can I help?',
ttsProvider: 'cartesia',
llmProvider: 'openai',
llmModel: 'gpt-4.1',
temperature: 0.7,
})
// List
const { data, nextCursor, hasMore } = await client.agents.list({ limit: 20 })
// Get
const agent = await client.agents.get('agent_abc123')
// Update
await client.agents.update('agent_abc123', {
systemPrompt: 'Updated prompt...',
temperature: 0.5,
})
// Delete
await client.agents.delete('agent_abc123')
// Chat
const reply = await client.agents.chat('agent_abc123', {
message: 'What are your hours?',
conversationId: 'conv_xyz', // optional, for multi-turn
})
// Speak (TTS with agent's voice)
const audioBuffer = await client.agents.speak('agent_abc123', {
text: 'Welcome to Acme Corp!',
format: 'mp3',
})
// Provision (agent + collection + initial content in one call)
const result = await client.agents.provision({
name: 'Knowledge Agent',
systemPrompt: 'Answer questions from the knowledge base.',
collection: { name: 'FAQ' },
initialContent: [
{ content: 'Our hours are 9am-5pm EST.', contentType: 'text' },
],
})Text-to-Speech
typescript
// Synthesize
const result = await client.tts.synthesize({
text: 'Hello world',
voiceId: 'default',
format: 'mp3', // mp3 | wav | ogg
speed: 1.0,
provider: 'cartesia', // or elevenlabs, deepgram, fish-audio, etc.
})
// List voices
const voices = await client.tts.listVoices()
// Get voice details
const voice = await client.tts.getVoice('voice_id')Speech-to-Text
typescript
// Transcribe from file
const result = await client.stt.transcribe(audioBlob, {
language: 'en',
mode: 'accurate', // accurate | fast
diarize: true,
timestamps: 'segment',
})
// Transcribe from URL
const result = await client.stt.transcribe('https://example.com/audio.mp3')
// Async transcription
const job = await client.stt.transcribeAsync(audioBlob)
const result = await client.stt.waitForJob(job.id, {
pollInterval: 1000,
timeout: 300000,
})RAG (Collections)
typescript
// Create collection
const collection = await client.rag.create({
name: 'Product Docs',
description: 'Product documentation for support agents',
})
// Ingest content
await client.rag.ingest(collection.id, {
content: 'Our return policy allows returns within 30 days...',
contentType: 'text',
chunkSize: 1000,
chunkOverlap: 200,
})
// Search
const results = await client.rag.search(collection.id, {
query: 'return policy',
limit: 5,
threshold: 0.7,
})
// List collections
const { data } = await client.rag.list()
// Delete collection
await client.rag.delete(collection.id)Sessions
typescript
// Create Twilio session
const session = await client.sessions.createTwilio({
agentId: 'agent_abc123',
from: '+18005551234',
to: '+19005551234',
})
// Connect WebSocket session
const ws = await client.sessions.connectAgent('agent_abc123', {
// WebSocket options
})Observability
typescript
// List session traces
const sessions = await client.observability.listSessions({
agentId: 'agent_abc123',
limit: 20,
})
// Get session detail
const detail = await client.observability.getSession('session_id')
// Get root cause analysis
const analysis = await client.observability.getSessionRootCause('session_id')Tasks (Outbound Calls)
typescript
// Dispatch an outbound call
const task = await client.tasks.dispatch('agent_abc123', {
phoneNumber: '+19005551234',
taskPrompt: 'Call the customer and confirm their appointment for tomorrow.',
})
// List tasks
const { data } = await client.tasks.list('agent_abc123')Error Handling
All API errors throw VoiceApiException:
typescript
import { VoiceApiException } from '@ph0ny/sdk'
try {
await client.agents.get('nonexistent')
} catch (err) {
if (err instanceof VoiceApiException) {
console.error(err.code) // 'NOT_FOUND'
console.error(err.message) // 'Agent not found'
console.error(err.status) // 404
}
}Provider Constants
The SDK re-exports canonical provider arrays:
typescript
import {
TTS_PROVIDERS, // ['cartesia', 'elevenlabs', 'deepgram', ...]
STT_PROVIDERS, // ['whisper', 'deepgram', 'elevenlabs', ...]
LLM_PROVIDERS, // ['openai', 'anthropic', 'groq']
VOICE_BACKENDS, // all voice backend types
BYOK_PROVIDERS, // providers supporting BYOK
} from '@ph0ny/sdk'