API Examples
Complete examples showing how to use the Control API.
Basic Flow
1. Create Session → 2. Init Client → 3. Use Avatar → 4. End Session
const BASE_URL = 'https://api.avatar.us.kaltura.ai/v1/avatar-session';
const KS = process.env.AVATAR_KS;
// Step 1: Create session
const createResponse = await fetch(`${BASE_URL}/create`, {
method: 'POST',
headers: {
Authorization: `KS ${KS}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
visualConfig: { avatarId: 'avatar-123' },
voiceConfig: { id: 'voice-456' },
}),
});
const { sessionId, token } = await createResponse.json();
// Step 2: Init client
const initResponse = await fetch(`${BASE_URL}/${sessionId}/init-client`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
});
const { whepUrl, turn } = await initResponse.json();
// Step 3: Make avatar speak
await fetch(`${BASE_URL}/${sessionId}/say-text`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: 'Hello from Kaltura Avatar!',
}),
});
// Step 4: End session
await fetch(`${BASE_URL}/${sessionId}/end`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
});
Complete Backend Implementation
Express Server
import express from 'express';
import fetch from 'node-fetch';
import cors from 'cors';
const app = express();
app.use(cors());
app.use(express.json());
const KS = process.env.AVATAR_KS;
const BASE_URL = 'https://api.avatar.us.kaltura.ai/v1/avatar-session';
// In-memory session storage (use database in production)
const sessions = new Map();
// Create session endpoint
app.post('/api/avatar/create-session', async (req, res) => {
try {
const { avatarId, voiceId } = req.body;
const response = await fetch(`${BASE_URL}/create`, {
method: 'POST',
headers: {
Authorization: `KS ${KS}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
visualConfig: { avatarId },
voiceConfig: voiceId ? { id: voiceId } : undefined,
}),
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const data = await response.json();
// Store session
sessions.set(data.sessionId, {
token: data.token,
createdAt: new Date(),
avatarId,
voiceId,
});
res.json({
sessionId: data.sessionId,
token: data.token,
});
} catch (error) {
console.error('Create session error:', error);
res.status(500).json({ error: 'Failed to create session' });
}
});
// Say text endpoint
app.post('/api/avatar/say-text', async (req, res) => {
try {
const { sessionId, token, text } = req.body;
// Validate session exists
if (!sessions.has(sessionId)) {
return res.status(404).json({ error: 'Session not found' });
}
// Validate text
if (!text || text.length === 0) {
return res.status(400).json({ error: 'Text is required' });
}
if (text.length > 1000) {
return res.status(400).json({ error: 'Text too long' });
}
const response = await fetch(`${BASE_URL}/${sessionId}/say-text`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ text }),
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const data = await response.json();
res.json(data);
} catch (error) {
console.error('Say text error:', error);
res.status(500).json({ error: 'Failed to say text' });
}
});
// Interrupt endpoint
app.post('/api/avatar/interrupt', async (req, res) => {
try {
const { sessionId, token } = req.body;
if (!sessions.has(sessionId)) {
return res.status(404).json({ error: 'Session not found' });
}
const response = await fetch(`${BASE_URL}/${sessionId}/interrupt`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const data = await response.json();
res.json(data);
} catch (error) {
console.error('Interrupt error:', error);
res.status(500).json({ error: 'Failed to interrupt' });
}
});
// End session endpoint
app.post('/api/avatar/end-session', async (req, res) => {
try {
const { sessionId, token } = req.body;
if (!sessions.has(sessionId)) {
return res.status(404).json({ error: 'Session not found' });
}
const response = await fetch(`${BASE_URL}/${sessionId}/end`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
// Remove session from storage
sessions.delete(sessionId);
const data = await response.json();
res.json(data);
} catch (error) {
console.error('End session error:', error);
res.status(500).json({ error: 'Failed to end session' });
}
});
// Keep-alive endpoint
app.post('/api/avatar/keep-alive', async (req, res) => {
try {
const { sessionId, token } = req.body;
if (!sessions.has(sessionId)) {
return res.status(404).json({ error: 'Session not found' });
}
const response = await fetch(`${BASE_URL}/${sessionId}/keep-alive`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
});
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const data = await response.json();
res.json(data);
} catch (error) {
console.error('Keep-alive error:', error);
res.status(500).json({ error: 'Failed to send keep-alive' });
}
});
// Health check
app.get('/health', (req, res) => {
res.json({
status: 'ok',
sessions: sessions.size,
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Python Example
import os
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
API_KEY = os.environ.get('AVATAR_KS')
BASE_URL = 'https://api.avatar.us.kaltura.ai/v1/avatar-session'
# Session storage
sessions = {}
@app.route('/api/avatar/create-session', methods=['POST'])
def create_session():
try:
data = request.json
avatar_id = data.get('avatarId')
voice_id = data.get('voiceId')
response = requests.post(
f'{BASE_URL}/create',
headers={
'Authorization': f'KS {API_KEY}',
'Content-Type': 'application/json'
},
json={
'visualConfig': {'avatarId': avatar_id},
'voiceConfig': {'id': voice_id} if voice_id else None
}
)
response.raise_for_status()
result = response.json()
# Store session
sessions[result['sessionId']] = {
'token': result['token'],
'avatarId': avatar_id
}
return jsonify({
'sessionId': result['sessionId'],
'token': result['token']
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/avatar/say-text', methods=['POST'])
def say_text():
try:
data = request.json
session_id = data.get('sessionId')
token = data.get('token')
text = data.get('text')
if session_id not in sessions:
return jsonify({'error': 'Session not found'}), 404
response = requests.post(
f'{BASE_URL}/{session_id}/say-text',
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
},
json={'text': text}
)
response.raise_for_status()
return jsonify(response.json())
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/avatar/end-session', methods=['POST'])
def end_session():
try:
data = request.json
session_id = data.get('sessionId')
token = data.get('token')
if session_id not in sessions:
return jsonify({'error': 'Session not found'}), 404
response = requests.post(
f'{BASE_URL}/{session_id}/end',
headers={'Authorization': f'Bearer {token}'}
)
response.raise_for_status()
# Remove session
del sessions[session_id]
return jsonify(response.json())
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
app.run(port=3000)
With Error Handling and Retries
async function createSessionWithRetry(maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(`${BASE_URL}/create`, {
method: 'POST',
headers: {
Authorization: `KS ${KS}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
visualConfig: { avatarId: 'avatar-123' },
}),
});
if (!response.ok) {
if (response.status >= 500 && attempt < maxRetries) {
// Retry on server errors
await new Promise((r) => setTimeout(r, 1000 * attempt));
continue;
}
throw new Error(`API error: ${response.status}`);
}
return await response.json();
} catch (error) {
if (attempt === maxRetries) {
throw error;
}
console.log(`Attempt ${attempt} failed, retrying...`);
await new Promise((r) => setTimeout(r, 1000 * attempt));
}
}
}
Next Steps
- Quick Start API - Step-by-step tutorial
- Server Controlled Example - Complete example
- Production Deployment - Best practices