TwinTone
  • TwinTone API
Powered by GitBook
On this page
  • TwinTone Video Agent API v1 - Overview
  • Base URL
  • Authentication
  • Endpoints
  • Error Handling
  • Example error response:
  • Rate Limiting
  • Endpoint details
  • Videos
  • POST /videos Generate a new video using a replica.
  • Request Body:
  • Response:
  • GET /videos/:id Retrieve details of a specific video generation.
  • Response:
  • DELETE /videos/:id Delete a specific video.
  • Response: HTTP 204 No Content
  • PATCH /videos/:id Update video name.
  • Request Body:
  • Response:
  • Conversations
  • GET /conversations List all conversations.
  • POST /conversations Create a new conversation.
  • Request Body:
  • Response:
  • GET /conversations/:id Retrieve details of a specific conversation.
  • Response:
  • POST /conversations/:id End an active conversation.
  • Response:
  • DELETE /conversations/:id Delete a conversation.
  • Response: HTTP 204 No Content
  • Personas
  • GET /personas List all personas.
  • Query Parameters:
  • Response:
  • POST /personas Create a new persona.
  • Request Body:
  • Response:
  • GET /personas/:id Get details of a specific persona.
  • Response:
  • PATCH /personas/:id Update a persona.
  • Request Body:
  • Response:
  • DELETE /personas/:id Delete a persona.
  • Response: HTTP 204 No Content
  • Speech
  • GET /speech List all speech generations.
  • Response:
  • POST /speech Generate new speech.
  • Request Body:
  • Response:
  • GET /speech/:id Get details of a specific speech generation.
  • Response:
  • DELETE /speech/:id Delete a speech generation.
  • Response: HTTP 204 No Content
  • PATCH /speech/:id Update speech name.
  • Request Body:
  • Response:
  • Error Handling
  • All API endpoints return appropriate HTTP status codes:
  • Error responses include a message field with details:
  • Error Response:
  • Rate Limiting
  • Code Examples
  • JavaScript (Node.js)
  • Python
  • GO
  • C#
  • Contact
  • Disclaimer

TwinTone API

TwinTone Video Agent API v1 - Overview

TwinTone’s Video Agent API empowers developers to seamlessly integrate AI-powered video agents into their applications, unlocking a new dimension of interactive and dynamic digital experiences. This REST API enables organizations to programmatically create and manage AI personas, facilitate real-time streaming conversations, and generate lifelike scripted speech.

Our documentation is optimized for efficiency, designed to fit within the context limits of leading large language models like Claude-3.5-Sonnet and ChatGPT-4o. Developers can use this guide to access a robust set of endpoints covering AI Agents videos, conversations, personas, and speech synthesis.

For best results, we recommend passing this documentation to an LLM for quick interpretation, but it's also structured for easy reading and navigation. Our API supports secure authentication via API keys, follows standard RESTful conventions, and includes detailed error handling for troubleshooting.

For API Keys, questions or support, feel free to reach out:

Recording Your Training Footage

Your journey to creating a personal AI Agent begins with a simple requirement: A 2-minute video of you engaging with the camera. There is no predefined script beyond the consent statement, you can discuss anything that showcases your natural speaking style and expertise.

Tips for Success

Our platform simplifies the first step. Use your webcam to capture the essence of your persona. Achieving the best possible AI Agent involves attention to detail.

Here’s how:

✅ Do: Utilize high-definition recording equipment, ensure proper lighting, and maintain focus on your face and upper body. Aim for a quiet, well-lit setting, and speak naturally. See more in Best Practices & Examples.

🚫 Don’t: Wear clothes that blend with the background, bulky accessories, or any headwear that obscures your face. Keep your gaze steady, minimize background distractions, and avoid excessive movement.

Consent

An integral part of the process involves reading a specific authorization phrase. This step confirms your consent and kicks off the AI Agent creation process.

“I, [FULL NAME], am currently speaking and give consent to TwinTone to create an AI clone of me by using the audio and video samples I provide. I understand that this AI clone can be used to create videos that look and sound like me.”

Best Practices & Examples:

Set Up: Environment

🌞 Lighting

Ensure your face is evenly lit with no shadows.

  • Example: If a window casts shadows on your face, change your orientation or use a ring light to even it out.

  • A large diffuse light will work best, providing consistent even and neutral lighting for the entire face.

  • This helps Phoenix to properly map your face, resulting in a better-looking video overall.

🔊 Noise

Your space should be silent or almost silent.

  • Avoid noise from air conditioning, construction, traffic, refrigerators, and conversations.

  • Choose rooms with minimal reverb to prevent sound amplification.

  • Clean audio, free from background noises, will produce the best audio output for your AI Agent.

🌆 Background

Keep your background clear.

  • Remove moving objects.

  • Ensure no other people are visible in the video.

Set Up: Equipment

📷 Camera & Placement

Use a high-quality camera with at least 2K pixels.

  • Examples: DSLR, newer laptops, iPhones, Samsung Galaxy, or Google Pixel.

  • Frames per second: Optimal FPS is 30, but 24-60 FPS is acceptable.

  • Distance: Maintain a distance of 3ft-6ft (or 0.9m-1.8m) from the camera.

  • Level: The camera should be at eye level.

  • Lens: Ensure the camera lens is clean of smudges.

🎙️ Microphone

Start with your phone or computer’s microphone.

  • A high-quality mic can mitigate background noise/echo.

  • For external USB or XLR mics:

    • Place the mic 1ft (0.3m) from your mouth, not exceeding 2-3ft (0.5-0.9m).

    • Position the mic at least 1 inch below your chin to avoid blocking your mouth.

  • Wireless earbuds, like Apple AirPods or Samsung Galaxy Buds, are not recommended due to poor mic quality.

👾 Software

Disable any software-based audio enhancements.

  • Turn off compressors, equalizers, noise suppression, etc., as we perform our own sound processing post-recording.

Set Up: Yourself

👀 Gaze

Maintain eye level with the camera and act naturally.

🗣️ Speaking Vibe & Pace

Be yourself and relax.

  • Pace: Take your time, don’t rush.

  • Pausing: Close your lips during pauses (the script will remind you).

  • Tone: Aim for an upbeat tone to keep content positive and engaging. Keep continuous eye contact with the camera. Be animated in your mouth, eyes, and cheeks.

  • Gestures: Keep hand gestures to a minimum and avoid blocking your face.

  • Mistakes: If you stumble, continue speaking. Perfection isn’t necessary.

🎅 Accessories & Beards

If possible, avoid beards, glasses, and accessories.

  • Our model is still being refined to better process these elements.

This comprehensive guide ensures you capture the highest quality footage for your AI Agent leading to a more authentic and engaging digital representation.

Base URL

API Base URL:

Authentication

All API requests require an API key for authentication. Include the key in the x-api-key header for every request.

Example: x-api-key: your-api-key


Endpoints

Replicas
Value

List all replicas

Get /replicas

Create a new replica

POST /replicas

Retrieve details of a specific replica

GET /replicas/:id

Delete a replica

DELETE /replicas/:id

Update replica’s name

PATCH /replicas/:id

Videos
Value

List all generated videos

GET /videos

Generate a new video

POST /videos

Get a specific video

GET /videos/:id

Delete a replica

DELETE /replicas/:id

Update replica’s name

PATCH /replicas/:id

Delete a video

DELETE /videos/:id

Update video name

PATCH /videos/:id

Conversations
Value

List all conversations

GET /conversations

Create a new conversation

POST /conversations

Get a specific conversation

GET /conversations/:id

End a conversation

POST /conversations/:id

Delete a conversation

DELETE /conversations/:id

Personas
Value

List all personas

/personas

Create a new persona

POST /personas

Get a specific video

GET /videos/:id

Get a specific persona

GET /personas/:id

Update a persona

PATCH /personas/:id

Delete a persona

DELETE /personas/:id

Personas
Value

List all speech generations

GET /speech

Generate new speech

POST /speech

Get specific speech generation

GET /speech/:id

Delete speech

DELETE /speech/:id

Update speech name

PATCH /speech/:id


Error Handling

The API uses standard HTTP status codes to indicate the success or failure of requests. Responses include an error message for troubleshooting.

  • All errors return semantic HTTP status codes

  • 502 status code likely indicates proxy error

Example error response:

 {
  "error": "InvalidRequest",
  "message": "The provided parameters are invalid.",
  "status": 400
}

Rate Limiting

  • Keep-alive connections are limited to 1 socket - can discuss if you have a use case that requires more.

  • Timeout set to 60 seconds for all requests

  • Exceeded Limits: Return status code 429.


Endpoint details

Videos

POST /videos Generate a new video using a replica.

Request Body:

{
  "replica_id": "string",
  "script": "string",
  "name": "string" // Optional
}

Response:

{
  "id": "string",
  "status": "processing",
  "created_at": "string"
}

GET /videos/:id Retrieve details of a specific video generation.

Response:

{
  "id": "string",
  "name": "string",
 "status": "processing|ready|failed", // Indicates the current processing state
  "url": "string", // Present only if status is "ready"
  "created_at": "string",
  "error": "string" // Present only if status is "failed"
}

DELETE /videos/:id Delete a specific video.

Response: HTTP 204 No Content

HTTP 204 No Content

PATCH /videos/:id Update video name.

Request Body:

{
  "name": "string"
}

Response:

{
  "id": "string",
  "name": "string",
  "status": "string",
  "updated_at": "string"
}

Conversations

GET /conversations List all conversations.

Query Parameters:

Name
Value

Page number

Page(optional)

Items per page

Limit(optional)

Filter by status (“active”|“ended”)

Status(optional)

{
  "conversations": [
    {
      "id": "string",
      "replica_id": "string",
      "status": "active|ended",
      "created_at": "string",
      "ended_at": "string" // Present if status is “ended” 
    }
  ],
  "pagination": {
    "total": 0,
    "page": 0,
    "pages": 0
  }
}

POST /conversations Create a new conversation.

Request Body:

{
  "replica_id": "string",
  "name": "string" // Optional
}

Response:

{
  "id": "string",
  "replica_id": "string",
  "status": "active",
  "created_at": "string"
}

GET /conversations/:id Retrieve details of a specific conversation.

Response:

{
  "id": "string",
  "replica_id": "string",
  "status": "active|ended",
  "created_at": "string",
  "ended_at": "string" // Only if ended
}

POST /conversations/:id End an active conversation.

Response:

{
  "id": "string",
  "status": "ended",
  "ended_at": "string"
}

DELETE /conversations/:id Delete a conversation.

Response: HTTP 204 No Content

HTTP 204 No Content

Personas

GET /personas List all personas.

Query Parameters:

Name
Value

Page number

Page(optional)

Items per page

Limit(optional)

Response:

{
  "personas": [
    {
      "id": "string",
      "name": "string",
      "description": "string",
      "created_at": "string"
    }
  ],
  "pagination": {
    "total": 0,
    "page": 0,
    "pages": 0
  }
}

POST /personas Create a new persona.

Request Body:

{
  "name": "string",
  "description": "string",
  "voice_settings": {
    "pitch": number,
    "speed": number
  }
}

Response:

{
  "id": "string",
  "name": "string",
  "description": "string",
  "created_at": "string"
}

GET /personas/:id Get details of a specific persona.

Response:

{
  "id": "string",
  "name": "string",
  "description": "string",
  "voice_settings": {
    "pitch": number,
    "speed": number
  },
  "created_at": "string"
}

PATCH /personas/:id Update a persona.

Request Body:

{
  "name": "string",
  "description": "string",
  "voice_settings": {
    "pitch": number,
    "speed": number
  }
}

Response:

{
  "id": "string",
  "name": "string",
  "description": "string",
  "voice_settings": {
    "pitch": number,
    "speed": number
  },
  "updated_at": "string"
}

DELETE /personas/:id Delete a persona.

Response: HTTP 204 No Content

 HTTP 204 No Content

Speech

GET /speech List all speech generations.

Query Parameters:

Name
Value

Page number

Page(optional)

Items per page

Limit(optional)

Filter by status

Status(optional)

Response:

{
  "speech": [
    {
      "id": "string",
      "text": "string",
      "status": "processing|ready|failed",
      "url": "string",
      "created_at": "string"
    }
  ],
  "pagination": {
    "total": 0,
    "page": 0,
    "pages": 0
  }
}

POST /speech Generate new speech.

Request Body:

{
  "text": "string",
  "persona_id": "string",
  "name": "string" // Optional 
}

Response:

{
  "id": "string",
  "status": "processing",
  "created_at": "string"
}

GET /speech/:id Get details of a specific speech generation.

Response:

{
  "id": "string",
  "text": "string",
  "status": "processing|ready|failed",
  "url": "string",
  "created_at": "string",
  "error": "string" // Only present if status is “failed”
}

DELETE /speech/:id Delete a speech generation.

Response: HTTP 204 No Content

HTTP 204 No Content

PATCH /speech/:id Update speech name.

Request Body:

{
  "name": "string"
}

Response:

{
  "id": "string",
  "name": "string",
  "status": "string",
  "updated_at": "string"
}

Error Handling

All API endpoints return appropriate HTTP status codes:

Headers

Name
Value

Success

200

Resource created

201

Success with no content

204

Bad request - invalid parameters

400

Unauthorized - invalid or missing API key

401

Resource not found

404

Rate limit exceeded

429

Internal server error

500

Bad gateway - proxy error

502

Error responses include a message field with details:

Error Response:

{
  "error": "string",
  "message": "string",
  "status": number
}

Rate Limiting

  • Keep-alive connections limited to 1 socket per client

  • Request timeout: 60 seconds

  • Rate limits are applied per API key

  • Exceeded limits return 429 status code


Code Examples

JavaScript (Node.js)

// JavaScript

// GET /replicas 
const getReplicas = async () => { 
const response = await fetch(‘https://api.twintone.ai/v1/replicas’, 
{ headers: {‘x-api-key’: ‘your-api-key’ } }); return response.json(); };

// POST /videos 
const createVideo = async () => { const response = await
fetch(‘https://api.twintone.ai/v1/video’, { method: ‘POST’, headers: {
‘x-api-key’: ‘your-api-key’, ‘Content-Type’: ‘application/json’ }, body:
JSON.stringify({ replica_id: ‘rep_123’, script: ‘Hello world!’, name: ‘My First
Video’ }) }); return response.json(); };

// PATCH /personas/:id 
const updatePersona = async (personaId) => { const
response = await fetch(`https://api.twintone.ai/v1/personas/${personaId}`, {
method: ‘PATCH’, headers: { ‘x-api-key’: ‘your-api-key’, ‘Content-Type’:
‘application/json’ }, body: JSON.stringify({ name: ‘Updated Name’, description:
‘New description’ }) }); return response.json(); };

// DELETE /speech/:id 
const deleteSpeech = async (speechId) => { await
fetch(`https://api.twintone.ai/v1/speech/${speechId}`, { method: ‘DELETE’,
headers: { ‘x-api-key’: ‘your-api-key’ } }); };

Python

# Python

import requests
API_KEY = 'your-api-key' BASE_URL = 'https://api.twintone.ai/v1' HEADERS =
{'x-api-key': API_KEY}

# GET /replicas

def get_replicas(): response = requests.get( f'{BASE_URL}/replicas',
headers=HEADERS ) return response.json()

# POST /videos

def create_video(): data = { 'replica_id': 'rep_123', 'script': 'Hello world!',
'name': 'My First Video' } response = requests.post( f'{BASE_URL}/videos',
headers=HEADERS, json=data ) return response.json()

# PATCH /personas/:id

def update_persona(persona_id): data = { 'name': 'Updated Name', 'description':
'New description' } response = requests.patch(
f'{BASE_URL}/personas/{persona_id}', headers=HEADERS, json=data ) return
response.json()

# DELETE /speech/:id

def delete_speech(speech_id): response = requests.delete(
f'{BASE_URL}/speech/{speech_id}', headers=HEADERS ) return response.status_code

GO

// Go

package main
import ( “bytes” “encoding/json” “fmt” “net/http” )

const ( apiKey = “your-api-key” baseURL = “https://api.twintone.ai/vi” )

// GET /replicas func getReplicas() (map[string]interface{}, error) { req, _ :=
http.NewRequest(“GET”, baseURL+“/replicas”, nil) req.Header.Add(“x-api-key”,
apiKey)

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
    return nil, err
}
defer resp.Body.Close()

var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result, nil
}

func createVideo() (map[string]interface{}, error) { data :=
map[string]string{ “replica_id”: “rep_123”, “script”: “Hello world!”, “name”:
“My First Video”, } jsonData, _ := json.Marshal(data)
req, _ := http.NewRequest("POST", baseURL+"/videos", bytes.NewBuffer(jsonData))
req.Header.Add("x-api-key", apiKey)
req.Header.Add("Content-Type", "application/json")

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
    return nil, err
}
defer resp.Body.Close()

var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
return result, nil
}

C#

using System; using System.Net.Http; using System.Text; 
using System.Text.Json; using System.Threading.Tasks;

class TwintoneClient { private readonly HttpClient _client; private const string 
BaseUrl = "https://api.twintone.ai/vi";public TwintoneClient(string apiKey)
{
    _client = new HttpClient();
    _client.DefaultRequestHeaders.Add("x-api-key", apiKey);
}

// GET /replicas
public async Task<string> GetReplicas()
{
    var response = await _client.GetAsync($"{BaseUrl}/replicas");
    return await response.Content.ReadAsStringAsync();
}

// POST /videos
public async Task<string> CreateVideo()
{
    var data = new
    {
        replica_id = "rep_123",
        script = "Hello world!",
        name = "My First Video"
    };

    var content = new StringContent(
        JsonSerializer.Serialize(data),
        Encoding.UTF8,
        "application/json"
    );

    var response = await _client.PostAsync($"{BaseUrl}/videos", content);
    return await response.Content.ReadAsStringAsync();
}

// PATCH /personas/:id
public async Task<string> UpdatePersona(string personaId)
{
    var data = new
    {
        name = "Updated Name",
        description = "New description"
    };

    var content = new StringContent(
        JsonSerializer.Serialize(data),
        Encoding.UTF8,
        "application/json"
    );

    var response = await _client.PatchAsync(
        $"{BaseUrl}/personas/{personaId}",
        content
    );
    return await response.Content.ReadAsStringAsync();
}

// DELETE /speech/:id
public async Task DeleteSpeech(string speechId)
{
    await _client.DeleteAsync($"{BaseUrl}/speech/{speechId}");
}

Contact

Disclaimer

The TwinTone API is provided "as is" without warranty of any kind. TwinTone disclaims all warranties, whether express, implied, or statutory, including without limitation any implied warranties of merchantability, fitness for a particular purpose, or non-infringement. TwinTone does not guarantee that the API will be available uninterrupted or error-free, and TwinTone will not be responsible for any damages or losses arising from the use of the API.

This documentation is subject to change. Please refer to the online version for the most up-to-date information.

Should you have any further questions, suggestions or feedback regarding this documentation, please contact:

📹
https://api.twintone.ai/v1
James@twintone.ai
James@twintone.ai
Page cover image