---
title: API Examples
url: https://docs.kaltura.com/docs/conversational-agents/agentic-avatars-sdk/control-api-examples
---

## 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

```javascript
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: { id: 'visual-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

```javascript
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 { visualId, voiceId } = req.body;

    const response = await fetch(`$\{BASE_URL\}/create`, {
      method: 'POST',
      headers: {
        Authorization: `KS $\{KS\}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        visualConfig: { id: visualId },
        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(),
      visualId,
      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

```python
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
        visual_id = data.get('visualId')
        voice_id = data.get('voiceId')

        response = requests.post(
            f'\{BASE_URL\}/create',
            headers={
                'Authorization': f'KS \{API_KEY\}',
                'Content-Type': 'application/json'
            },
            json={
                'visualConfig': {'id': visual_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'],
            'visualId': visual_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

```javascript
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: { id: 'visual-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](/docs/conversational-agents/agentic-avatars-sdk/quick-start-api)** - Step-by-step tutorial
- **[Server Controlled Example](/docs/conversational-agents/agentic-avatars-sdk/examples-server-controlled)** - Complete example
