API Plateforme ePV ePV Platform API ePV Platform API API Piattaforma ePV

Documentation complète de l'API pour les services de transcription audio et de modèles de langage. Créez des applications d'IA puissantes avec un traitement vocal en temps réel et une génération de texte intelligente. Comprehensive API documentation for audio transcription and Large Language Model services. Build powerful AI applications with real-time speech processing and intelligent text generation. Umfassende API-Dokumentation für Audio-Transkriptions- und Sprachmodell-Services. Erstellen Sie leistungsstarke KI-Anwendungen mit Echtzeit-Sprachverarbeitung und intelligenter Textgenerierung. Documentazione completa dell'API per i servizi di trascrizione audio e modelli linguistici. Crea applicazioni AI potenti con elaborazione vocale in tempo reale e generazione intelligente di testo.

Dernière Mise à Jour (7 Novembre 2025): Latest Update (November 7, 2025): Letztes Update (7. November 2025): Ultimo Aggiornamento (7 Novembre 2025): Documentation API simplifiée se concentrant sur les endpoints essentiels pour la transcription, les LLM et le suivi d'utilisation. Streamlined API documentation focusing on essential endpoints for transcription, LLM, and usage tracking. Optimierte API-Dokumentation mit Fokus auf wesentliche Endpunkte für Transkription, LLMs und Nutzungsüberwachung. Documentazione API semplificata concentrata su endpoint essenziali per trascrizione, LLM e monitoraggio dell'utilizzo.

Introduction Introduction Einführung Introduzione

L'API de la plateforme ePV fournit des services de transcription audio et de LLM de pointe conçus pour les applications d'entreprise. Notre plateforme combine la reconnaissance vocale optimisée pour le français avec des modèles de langage puissants pour offrir des solutions d'IA précises et évolutives. The ePV Platform API provides state-of-the-art audio transcription and LLM services designed for enterprise applications. Our platform combines French-optimized speech recognition with powerful language models to deliver accurate, scalable AI solutions. Die ePV Platform API bietet hochmoderne Audio-Transkriptions- und LLM-Services für Unternehmensanwendungen. Unsere Plattform kombiniert französisch-optimierte Spracherkennung mit leistungsstarken Sprachmodellen, um präzise, skalierbare KI-Lösungen zu liefern. L'API della piattaforma ePV fornisce servizi di trascrizione audio e LLM all'avanguardia progettati per applicazioni aziendali. La nostra piattaforma combina il riconoscimento vocale ottimizzato per il francese con potenti modelli linguistici per fornire soluzioni AI accurate e scalabili.

Haute Précision High Accuracy Hohe Genauigkeit Alta Precisione

Modèles Whisper optimisés pour le français avec diarisation des locuteurs pour une transcription précise multi-locuteurs. French-optimized Whisper models with speaker diarization for precise multi-speaker transcription. Französisch-optimierte Whisper-Modelle mit Sprecher-Diarisierung für präzise Multi-Sprecher-Transkription. Modelli Whisper ottimizzati per il francese con diarizzazione degli speaker per trascrizione precisa multi-parlante.

Traitement en Temps Réel Real-time Processing Echtzeit-Verarbeitung Elaborazione in Tempo Reale

Streaming WebSocket pour la transcription en direct avec suivi automatique de l'utilisation et gestion des sessions. WebSocket streaming for live transcription with automatic usage tracking and session management. WebSocket-Streaming für Live-Transkription mit automatischer Nutzungsüberwachung und Sitzungsverwaltung. Streaming WebSocket per trascrizione live con monitoraggio automatico dell'utilizzo e gestione delle sessioni.

Sécurité Entreprise Enterprise Security Unternehmenssicherheit Sicurezza Aziendale

Authentification basée sur des tokens avec journalisation d'audit complète. Token-based authentication with comprehensive audit logging. Token-basierte Authentifizierung mit umfassender Audit-Protokollierung. Autenticazione basata su token con logging di audit completo.

Authentification Authentifizierung Autenticazione

Toutes les requêtes API nécessitent une authentification utilisant des tokens Bearer. Incluez votre token API dans l'en-tête Authorization : Alle API-Anfragen erfordern Authentifizierung mit Bearer-Tokens. Fügen Sie Ihr API-Token in den Authorization-Header ein: Tutte le richieste API richiedono autenticazione usando token Bearer. Includi il tuo token API nell'header Authorization:

Authorization: Bearer epv_1234567890abcdef...

Vous pouvez obtenir des tokens API depuis le tableau de bord de la plateforme ePV à Sie können API-Tokens vom ePV Platform Dashboard erhalten unter Puoi ottenere token API dal dashboard della piattaforma ePV su dashboard.mayorsoftware.ch

URLs de Base Basis-URLs URL di Base

Services de Transcription : Transkriptions-Services: Servizi di Trascrizione:
https://api.mayorsoftware.ch/v1
Transcription WebSocket : WebSocket-Transkription: Trascrizione WebSocket:
wss://api.mayorsoftware.ch/v1/asr

Transcription WebSocket en Temps Réel WebSocket Live-Transkription Trascrizione WebSocket in Tempo Reale

Transcription Audio en Temps Réel Echtzeit-Audio-Transkription Trascrizione Audio in Tempo Reale
WS wss://api.mayorsoftware.ch/v1/asr

Établir une connexion WebSocket pour la transcription audio en temps réel avec support de la diarisation des locuteurs. Stellen Sie eine WebSocket-Verbindung für Echtzeit-Audio-Transkription mit Unterstützung für Sprecher-Diarisierung her. Stabilire una connessione WebSocket per la trascrizione audio in tempo reale con supporto per la diarizzazione degli speaker.

Paramètres de Connexion Verbindungsparameter Parametri di Connessione

Paramètre Parameter Parametro Type Typ Tipo Requis Erforderlich Richiesto Description Beschreibung Descrizione
token query requis erforderlich richiesto Token API pour l'authentification (paramètre d'URL) API-Token für Authentifizierung (URL-Parameter) Token API per autenticazione (parametro URL)
language query optionnel optional opzionale Langue cible (défaut: fr) Zielsprache (Standard: fr) Lingua di destinazione (predefinito: fr)
enable_diarization query optionnel optional opzionale Activer la diarisation des locuteurs (défaut: true) Sprecher-Diarisierung aktivieren (Standard: true) Abilitare diarizzazione speaker (predefinito: true)

Limites de Taux (Rate Limiting) Rate Limiting Rate-Limiting Rate Limiting

Pour protéger le service contre la surcharge, les limites suivantes s'appliquent par token API: To protect the service against overload, the following limits apply per API token: Zum Schutz des Dienstes vor Überlastung gelten folgende Limits pro API-Token: Per proteggere il servizio dal sovraccarico, si applicano i seguenti limiti per token API:

  • Maximum 3 connexions WebSocket simultanées par token Maximum 3 simultaneous WebSocket connections per token Maximal 3 gleichzeitige WebSocket-Verbindungen pro Token Massimo 3 connessioni WebSocket simultanee per token
  • Maximum 10 nouvelles connexions par minute par token Maximum 10 new connections per minute per token Maximal 10 neue Verbindungen pro Minute pro Token Massimo 10 nuove connessioni al minuto per token

Si ces limites sont dépassées, la connexion WebSocket sera fermée avec le code 1008 (Policy Violation). If these limits are exceeded, the WebSocket connection will be closed with code 1008 (Policy Violation). Wenn diese Limits überschritten werden, wird die WebSocket-Verbindung mit Code 1008 (Richtlinienverletzung) geschlossen. Se questi limiti vengono superati, la connessione WebSocket verrà chiusa con codice 1008 (Violazione delle Policy).

Protocole WebSocket WebSocket Protocol WebSocket-Protokoll Protocollo WebSocket

Séquence de Connexion Connection Sequence Verbindungssequenz Sequenza di Connessione

  1. Connexion WebSocket
    wss://api.mayorsoftware.ch/v1/asr?token=epv_xxx&enable_diarization=true
  2. Message de configuration du serveur (Server → Client)

    Le serveur envoie immédiatement après la connexion :

    {
      "type": "config",
      "useAudioWorklet": false
    }
  3. Message de configuration des signatures vocales (Client → Server)

    OBLIGATOIRE si enable_diarization=true : Le client DOIT envoyer les signatures vocales dans les 5 secondes, sinon la diarisation sera désactivée :

    {
      "type": "config",
      "voice_signatures": [
        {
          "name": "Alice",
          "embedding": [0.123, -0.456, 0.789, ...]  // 512 dimensions
        },
        {
          "name": "Bob",
          "embedding": [0.321, 0.654, -0.987, ...]
        }
      ]
    }

    Note : Si aucune signature n'est disponible mais que la diarisation est activée, envoyez un tableau vide : "voice_signatures": []

  4. Accusé de réception des signatures (Server → Client)

    Le serveur confirme la réception :

    {
      "type": "config_ack",
      "signatures_received": 2
    }
  5. Envoi des données audio

    Le client peut maintenant envoyer des données audio binaires en continu.

Types de Messages Message Types Nachrichtentypen Tipi di Messaggi

1️⃣ Audio Data (Client → Server) - Binary

Envoyez les données audio brutes (WebM/Opus) directement via WebSocket. Pas besoin de JSON ou de base64. Send raw audio data (WebM/Opus) directly via WebSocket. No JSON or base64 encoding needed. Senden Sie rohe Audiodaten (WebM/Opus) direkt über WebSocket. Kein JSON oder Base64-Kodierung erforderlich. Invia dati audio grezzi (WebM/Opus) direttamente tramite WebSocket. Non è necessaria la codifica JSON o base64.

// Send binary audio data directly
ws.send(audioBlobData);

2️⃣ Transcription Result (Server → Client) - JSON

{
  "status": "active_transcription",
  "lines": [
    {
      "speaker": 0,
      "text": "Transcribed text segment",
      "start": "00:00:00.000",
      "end": "00:00:03.200"
    }
  ],
  "buffer_transcription": "",
  "buffer_diarization": "",
  "remaining_time_transcription": 0.0,
  "remaining_time_diarization": 0.0,
  "token_usage": {
    "tokens_consumed": 0.5,
    "base_tokens": 0.5,
    "diarization_tokens": 0.0,
    "voice_signature_tokens": 0.0,
    "llm_tokens": 0.0,
    "duration_minutes": 0.5,
    "billing_metadata": {}
  }
}

3️⃣ End Session (Client → Server) - JSON

Pour terminer proprement une session de transcription, envoyez ce message de contrôle : To properly end a transcription session, send this control message: Um eine Transkriptionssitzung ordnungsgemäß zu beenden, senden Sie diese Kontrollnachricht: Per terminare correttamente una sessione di trascrizione, invia questo messaggio di controllo:

{
  "type": "end_session"
}

Important : Ceci permet au serveur de traiter tout l'audio restant dans le buffer et d'envoyer les derniers résultats avant de fermer la connexion. Le serveur répondra avec un message ready_to_stop quand tout est terminé. Important: This allows the server to process any remaining audio in the buffer and send final results before closing the connection. The server will respond with a ready_to_stop message when complete.

4️⃣ Ready to Stop (Server → Client) - JSON

Le serveur envoie ce message après avoir traité tous les résultats suite à un end_session : The server sends this message after processing all results following an end_session:

{
  "type": "ready_to_stop"
}

Le client peut maintenant fermer la connexion WebSocket en toute sécurité avec ws.close(). The client can now safely close the WebSocket connection with ws.close().

Note: Les champs buffer_transcription, buffer_diarization, remaining_time_transcription, remaining_time_diarization et token_usage sont optionnels et peuvent ne pas être présents dans toutes les réponses.

Cas Spéciaux Special Cases Sonderfälle Casi Speciali

Diarisation désactivée (enable_diarization=false) Diarization disabled (enable_diarization=false)

Le serveur NE DEMANDE PAS de message de configuration avec les signatures vocales. Vous pouvez commencer à envoyer l'audio immédiatement après avoir reçu le message {"type": "config", "useAudioWorklet": false}. The server DOES NOT REQUEST a configuration message with voice signatures. You can start sending audio immediately after receiving the {"type": "config", "useAudioWorklet": false} message.

Timeout du message de configuration Configuration message timeout

Si enable_diarization=true et qu'aucun message de configuration n'est reçu dans les 5 secondes, la diarisation sera DÉSACTIVÉE. Les signatures vocales sont obligatoires pour utiliser la diarisation. If enable_diarization=true and no configuration message is received within 5 seconds, diarization will be DISABLED. Voice signatures are required to use diarization.

Reconnexion Reconnection

Pour démarrer une nouvelle session après une déconnexion, vous devez établir une nouvelle connexion WebSocket et recommencer le processus complet (y compris l'envoi du message de configuration si nécessaire). To start a new session after disconnection, you must establish a new WebSocket connection and restart the complete process (including sending the configuration message if needed).

Exemples de Code Code Examples Codebeispiele Esempi di Codice

const apiToken = 'epv_your_token_here';
const enableDiarization = true;
const voiceSignatures = [  // Get from /generate_signatures endpoint
  { name: 'Alice', embedding: [/* 512 dimensions */] },
  { name: 'Bob', embedding: [/* 512 dimensions */] }
];

const wsUrl = `wss://api.mayorsoftware.ch/v1/asr?token=${encodeURIComponent(apiToken)}&enable_diarization=${enableDiarization}`;

const ws = new WebSocket(wsUrl);
let mediaRecorder = null;
let configReceived = false;

ws.onopen = () => {
  console.log('WebSocket connected, waiting for server config...');
};

ws.onmessage = async (event) => {
  const data = JSON.parse(event.data);
  
  // 1. Handle initial server config
  if (data.type === 'config' && !configReceived) {
    console.log('Received server config:', data);
    configReceived = true;
    
    // 2. Send voice signatures if diarization is enabled
    if (enableDiarization && voiceSignatures.length > 0) {
      console.log('Sending voice signatures...');
      ws.send(JSON.stringify({
        type: 'config',
        voice_signatures: voiceSignatures
      }));
    } else if (enableDiarization) {
      // Send empty array if no signatures but diarization enabled
      ws.send(JSON.stringify({
        type: 'config',
        voice_signatures: []
      }));
    }
    
    // 3. Start audio capture after config is sent (or skipped)
    if (!enableDiarization || voiceSignatures) {
      startAudioCapture();
    }
    return;
  }
  
  // 4. Handle signature acknowledgment
  if (data.type === 'config_ack') {
    console.log(`Signatures confirmed: ${data.signatures_received} received`);
    startAudioCapture();
    return;
  }
  
  // 5. Handle ready_to_stop signal
  if (data.type === 'ready_to_stop') {
    console.log('Server ready to stop, closing connection...');
    ws.close();
    return;
  }
  
  // 6. Handle transcription results
  if (data.status === 'active_transcription' && data.lines) {
    data.lines.forEach(line => {
      if (line.text && line.text.trim()) {
        console.log(`Speaker ${line.speaker}: ${line.text}`);
      }
    });
    
    // Check for token usage information
    if (data.token_usage) {
      console.log(`Tokens consumed: ${data.token_usage.tokens_consumed}`);
    }
  }
};

function startAudioCapture() {
  console.log('Starting audio capture...');
  navigator.mediaDevices.getUserMedia({ audio: true })
    .then(stream => {
      mediaRecorder = new MediaRecorder(stream, {
        mimeType: 'audio/webm;codecs=opus'
      });
      
      mediaRecorder.ondataavailable = (event) => {
        if (event.data.size > 0 && ws.readyState === WebSocket.OPEN) {
          // Send raw binary audio data
          ws.send(event.data);
        }
      };
      
      mediaRecorder.start(250); // Send data every 250ms
      console.log('Audio capture started');
    })
    .catch(err => console.error('Audio capture error:', err));
}

function stopRecording() {
  console.log('⏹️ Stopping recording...');
  if (mediaRecorder && mediaRecorder.state !== 'inactive') {
    mediaRecorder.stop();
  }
  
  // Send end_session message for graceful shutdown
  if (ws.readyState === WebSocket.OPEN) {
    ws.send(JSON.stringify({ type: 'end_session' }));
    console.log('Sent end_session, waiting for server confirmation...');
  }
}

ws.onerror = (error) => {
  console.error('WebSocket error:', error);
};

ws.onclose = (event) => {
  console.log(`WebSocket disconnected (code: ${event.code}, reason: ${event.reason || 'none'})`);
  if (mediaRecorder && mediaRecorder.state !== 'inactive') {
    mediaRecorder.stop();
  }
};

// Usage: Call stopRecording() when user wants to end the session
// setTimeout(() => stopRecording(), 60000); // Example: stop after 60 seconds
import asyncio
import websockets
import json
import pyaudio

async def transcribe_live():
    api_token = "epv_your_token_here"
    uri = f"wss://api.mayorsoftware.ch/v1/asr?token={api_token}"
    
    async with websockets.connect(uri) as websocket:
        # Audio configuration
        chunk = 1024
        format = pyaudio.paInt16
        channels = 1
        rate = 16000
        
        audio = pyaudio.PyAudio()
        stream = audio.open(
            format=format,
            channels=channels,
            rate=rate,
            input=True,
            frames_per_buffer=chunk
        )
        
        async def send_audio():
            while True:
                # Read and send raw audio data
                data = stream.read(chunk)
                await websocket.send(data)
                await asyncio.sleep(0.05)
        
        async def receive_transcription():
            async for message in websocket:
                data = json.loads(message)
                if data.get("status") == "active_transcription" and data.get("lines"):
                    for line in data["lines"]:
                        if line.get("text") and line["text"].strip():
                            print(f"Speaker {line['speaker']}: {line['text']}")
                    
                    # Check for token usage information
                    if data.get("token_usage"):
                        tokens = data["token_usage"].get("tokens_consumed", 0)
                        print(f"Tokens consumed: {tokens}")
        
        await asyncio.gather(send_audio(), receive_transcription())

asyncio.run(transcribe_live())

Generate Voice Signatures

Generate Speaker Embeddings
POST https://api.mayorsoftware.ch/v1/generate_signatures

Upload audio samples for each speaker and generate neural embeddings (512-dimensional vectors). These embeddings can then be used for speaker identification in transcription requests.

Request Parameters

Parameter Type Required Description
audio_files file[] required Audio files containing speaker voice samples (minimum 1 second each)
speaker_names string required JSON array of speaker names matching the audio files order

Response Format

{
  "success": true,
  "signatures": [
    {
      "name": "John Doe",
      "embedding": [0.123, -0.456, 0.789, ...] // 512-dimensional vector
    },
    {
      "name": "Jane Smith",
      "embedding": [0.321, 0.654, -0.987, ...]
    }
  ],
  "count": 2
}

Code Examples

const formData = new FormData();
formData.append('audio_files', johnAudioFile);
formData.append('audio_files', janeAudioFile);
formData.append('speaker_names', JSON.stringify(['John Doe', 'Jane Smith']));

const response = await fetch('https://api.mayorsoftware.ch/v1/generate_signatures', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`
  },
  body: formData
});

const data = await response.json();
console.log(`Generated ${data.count} signatures`);

// Save signatures for later use in transcription
localStorage.setItem('voiceSignatures', JSON.stringify(data.signatures));
import requests

# Prepare audio files
files = [
    ('audio_files', ('john.wav', open('john.wav', 'rb'), 'audio/wav')),
    ('audio_files', ('jane.wav', open('jane.wav', 'rb'), 'audio/wav'))
]

data = {
    'speaker_names': '["John Doe", "Jane Smith"]'
}

response = requests.post(
    'https://api.mayorsoftware.ch/v1/generate_signatures',
    headers={'Authorization': f'Bearer {token}'},
    files=files,
    data=data
)

result = response.json()
print(f"Generated {result['count']} signatures")

# Save signatures for later use
signatures = result['signatures']

Synchronous Transcription

Upload and Transcribe Audio File
POST https://api.mayorsoftware.ch/v1/transcribe/sync

Upload an audio file and receive the complete transcription synchronously. Best for smaller files.

Request Parameters

Parameter Type Required Description
audio file required Audio file (WAV, MP3, M4A, FLAC, OGG)
diarization string optional Enable speaker diarization ("true"/"false", default: server config)
voice_signatures string optional JSON string of pre-generated embeddings from /generate_signatures (e.g., '[{"name":"John","embedding":[...]}]')
speaker_names string optional (Deprecated) Speaker names are now embedded in voice_signatures JSON
use_voice_signatures string optional Enable voice signature matching ("true"/"false")
voice_similarity_threshold string optional Similarity threshold for voice matching (0.0-1.0, default: 0.18)

Response Format

{
  "text": "Full transcription text",
  "segments": [
    {
      "text": "First segment",
      "speaker": 0,
      "start": "00:00:00.000",
      "end": "00:00:03.200"
    }
  ],
  "filename": "audio.wav",
  "duration": 15.3,
  "language": "fr",
  "diarization_enabled": true,
  "voice_signatures_used": false,
  "diarization_summary": {
    "total_segments": 5,
    "unique_speakers": 2,
    "speaker_durations": {
      "0": 8.5,
      "1": 6.8
    }
  },
  "speaker_info": {},
  "processing_mode": "sync",
  "token_usage": {
    "tokens_consumed": 0.5,
    "base_tokens": 0.25,
    "diarization_tokens": 0.125,
    "voice_signature_tokens": 0.0,
    "llm_tokens": 0.0,
    "duration_minutes": 0.255,
    "billing_metadata": {
      "filename": "audio.wav",
      "duration_seconds": 15.3,
      "num_segments": 5,
      "unique_speakers": 2,
      "processing_mode": "sync"
    }
  }
}

Code Examples

const transcribeFile = async (audioFile) => {
  // Step 1: Generate voice signatures (if using known speakers)
  const sigFormData = new FormData();
  sigFormData.append('audio_files', speakerAudioFile1); // Sample from speaker 1
  sigFormData.append('audio_files', speakerAudioFile2); // Sample from speaker 2
  sigFormData.append('speaker_names', JSON.stringify(['Alice', 'Bob']));

  const sigResponse = await fetch('https://api.mayorsoftware.ch/generate_signatures', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer epv_your_token_here'
    },
    body: sigFormData
  });

  const { signatures } = await sigResponse.json();
  // signatures = [{name: 'Alice', embedding: [...]}, {name: 'Bob', embedding: [...]}]

  // Step 2: Transcribe with voice signatures
  const formData = new FormData();
  formData.append('audio', audioFile);
  formData.append('diarization', 'true');
  formData.append('use_voice_signatures', 'true');
  formData.append('voice_signatures', JSON.stringify(signatures)); // Send as JSON string
  formData.append('voice_similarity_threshold', '0.18');

  try {
    const response = await fetch('https://api.mayorsoftware.ch/v1/transcribe/sync', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer epv_your_token_here'
      },
      body: formData
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const result = await response.json();
    console.log('Transcription:', result.text);
    console.log('Duration:', result.duration);
    console.log('Language:', result.language);
    
    // Process segments with speaker information
    result.segments.forEach(segment => {
      console.log(`Speaker ${segment.speaker} (${segment.start}-${segment.end}): ${segment.text}`);
    });
    
    // Display diarization summary
    if (result.diarization_summary) {
      console.log(`Total segments: ${result.diarization_summary.total_segments}`);
      console.log(`Unique speakers: ${result.diarization_summary.unique_speakers}`);
    }
    
    // Display token usage
    if (result.token_usage) {
      console.log(`Tokens consumed: ${result.token_usage.tokens_consumed}`);
    }

  } catch (error) {
    console.error('Transcription failed:', error);
  }
};

// Usage with file input
document.getElementById('fileInput').addEventListener('change', (event) => {
  const file = event.target.files[0];
  if (file) {
    transcribeFile(file);
  }
});
import requests

def transcribe_audio_file(file_path, enable_diarization=True):
    url = 'https://api.mayorsoftware.ch/v1/transcribe/sync'
    
    headers = {
        'Authorization': 'Bearer epv_your_token_here'
    }
    
    files = {
        'audio': open(file_path, 'rb')
    }
    
    data = {
        'diarization': str(enable_diarization).lower()
    }
    
    try:
        response = requests.post(url, headers=headers, files=files, data=data)
        response.raise_for_status()
        
        result = response.json()
        
        print(f"Transcription: {result['text']}")
        print(f"Duration: {result['duration']}s")
        print(f"Language: {result['language']}")
        
        # Print diarization summary
        if result.get('diarization_summary'):
            summary = result['diarization_summary']
            print(f"Speakers: {summary['unique_speakers']}")
            print(f"Total segments: {summary['total_segments']}")
        
        # Print segments with timestamps
        for segment in result['segments']:
            print(f"Speaker {segment['speaker']} ({segment['start']}-{segment['end']}): {segment['text']}")
        
        # Print token usage
        if result.get('token_usage'):
            print(f"Tokens consumed: {result['token_usage']['tokens_consumed']}")
            
        return result
        
    except requests.exceptions.RequestException as e:
        print(f"Error: {e}")
        return None
    finally:
        files['audio'].close()

# Usage
result = transcribe_audio_file('meeting_recording.wav')

Asynchronous Transcription - Submit

Submit Audio for Background Processing
POST https://api.mayorsoftware.ch/v1/transcribe/submit

Submit an audio file for asynchronous processing. Returns a task ID to track progress and retrieve results.

Request Parameters

Parameter Type Required Description
audio file required Audio file (WAV, MP3, M4A, FLAC, OGG)
diarization string optional Enable speaker diarization ("true"/"false", default: server config)
voice_signatures string optional JSON string of pre-generated embeddings from /generate_signatures (e.g., '[{"name":"John","embedding":[...]}]')
voice_similarity_threshold string optional Cosine similarity threshold for voice matching (default: "0.18", range: "0.0"-"1.0")
speaker_names string optional (Deprecated) Speaker names are now embedded in voice_signatures JSON
use_voice_signatures string optional Enable voice signature matching ("true"/"false")

Response Format

{
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "queued",
  "message": "Task submitted successfully. Use /transcribe/status/{task_id} to check progress.",
  "token_usage": {
    "tokens_consumed": 0.5,
    "base_tokens": 0.25,
    "diarization_tokens": 0.125,
    "voice_signature_tokens": 0.0,
    "llm_tokens": 0.0,
    "duration_minutes": 0.255,
    "billing_metadata": {
      "filename": "audio.wav",
      "task_id": "550e8400-e29b-41d4-a716-446655440000",
      "processing_mode": "async",
      "estimated": true
    }
  }
}

Code Examples

const submitAsyncTranscription = async (audioFile, signatures = null) => {
  // Step 1: Generate voice signatures if needed
  let voiceSignatures = signatures;
  if (!voiceSignatures && speakerAudioSamples) {
    const sigFormData = new FormData();
    speakerAudioSamples.forEach(sample => {
      sigFormData.append('audio_files', sample);
    });
    sigFormData.append('speaker_names', JSON.stringify(['Alice', 'Bob']));

    const sigResponse = await fetch('https://api.mayorsoftware.ch/generate_signatures', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer epv_your_token_here'
      },
      body: sigFormData
    });

    const sigResult = await sigResponse.json();
    voiceSignatures = sigResult.signatures;
  }

  // Step 2: Submit transcription task
  const formData = new FormData();
  formData.append('audio', audioFile);
  formData.append('diarization', 'true');
  if (voiceSignatures) {
    formData.append('use_voice_signatures', 'true');
    formData.append('voice_signatures', JSON.stringify(voiceSignatures));
    formData.append('voice_similarity_threshold', '0.18');
  }

  try {
    const response = await fetch('https://api.mayorsoftware.ch/v1/transcribe/submit', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer epv_your_token_here'
      },
      body: formData
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const result = await response.json();
    console.log('Task submitted:', result.task_id);
    console.log('Status:', result.status);
    console.log('Message:', result.message);
    
    // Display estimated token usage
    if (result.token_usage) {
      console.log(`Estimated tokens: ${result.token_usage.tokens_consumed}`);
    }
    
    return result.task_id;

  } catch (error) {
    console.error('Submission failed:', error);
    return null;
  }
};

// Usage
const fileInput = document.getElementById('fileInput');
fileInput.addEventListener('change', async (event) => {
  const file = event.target.files[0];
  if (file) {
    const taskId = await submitAsyncTranscription(file);
    if (taskId) {
      // Poll for results
      pollTranscriptionStatus(taskId);
    }
  }
});
import requests
import json

def generate_signatures(audio_files, speaker_names):
    """Generate voice signatures from audio samples."""
    url = 'https://api.mayorsoftware.ch/generate_signatures'
    
    headers = {
        'Authorization': 'Bearer epv_your_token_here'
    }
    
    files = [('audio_files', open(f, 'rb')) for f in audio_files]
    data = {
        'speaker_names': json.dumps(speaker_names)
    }
    
    try:
        response = requests.post(url, headers=headers, files=files, data=data)
        response.raise_for_status()
        return response.json()['signatures']
    finally:
        for _, file_obj in files:
            file_obj.close()

def submit_async_transcription(file_path, signatures=None):
    url = 'https://api.mayorsoftware.ch/v1/transcribe/submit'
    
    headers = {
        'Authorization': 'Bearer epv_your_token_here'
    }
    
    files = {
        'audio': open(file_path, 'rb')
    }
    
    data = {
        'diarization': 'true'
    }
    
    # Add voice signatures if provided
    if signatures:
        data['use_voice_signatures'] = 'true'
        data['voice_signatures'] = json.dumps(signatures)
        data['voice_similarity_threshold'] = '0.18'
    
    try:
        response = requests.post(url, headers=headers, files=files, data=data)
        response.raise_for_status()
        
        result = response.json()
        
        print(f"Task submitted: {result['task_id']}")
        print(f"Status: {result['status']}")
        print(f"Message: {result['message']}")
        
        # Display estimated token usage
        if result.get('token_usage'):
            print(f"Estimated tokens: {result['token_usage']['tokens_consumed']}")
        
        return result['task_id']
        
    except requests.exceptions.RequestException as e:
        print(f"Error: {e}")
        return None
    finally:
        files['audio'].close()

# Usage
task_id = submit_async_transcription('large_meeting.mp3')
if task_id:
    print(f"Track your task at: https://api.mayorsoftware.ch/v1/transcribe/status/{task_id}")

Check Transcription Status

Get Task Status
GET https://api.mayorsoftware.ch/v1/transcribe/status/{task_id}

Check the processing status of an asynchronous transcription task.

Response Format

{
  "task_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "progress": 100,
  "current_step": "Completed successfully",
  "created_at": "2025-11-07T10:30:00Z",
  "started_at": "2025-11-07T10:30:01Z",
  "completed_at": "2025-11-07T10:31:45Z",
  "filename": "audio.wav",
  "duration": 104.5,
  "error": null
}

Status Values

Status Description
queued Job is waiting to be processed
processing Job is currently being processed
completed Job completed successfully
failed Job failed with error
cancelled Job was cancelled by user

Get Transcription Result

Retrieve Completed Transcription
GET https://api.mayorsoftware.ch/v1/transcribe/result/{task_id}

Retrieve the transcription result for a completed task.

Response Format

{
  "text": "Complete transcription text",
  "segments": [
    {
      "text": "Segment text",
      "speaker": 0,
      "start": "00:00:00.000",
      "end": "00:00:03.200"
    }
  ],
  "filename": "audio.wav",
  "duration": 120.5,
  "language": "fr",
  "diarization_enabled": true,
  "diarization_summary": {
    "total_segments": 25,
    "unique_speakers": 3,
    "speaker_durations": {
      "0": 45.2,
      "1": 38.7,
      "2": 36.6
    }
  },
  "speaker_info": {},
  "processing_mode": "background",
  "token_usage": {
    "tokens_consumed": 2.5,
    "base_tokens": 2.0,
    "diarization_tokens": 0.5,
    "voice_signature_tokens": 0.0,
    "llm_tokens": 0.0,
    "duration_minutes": 2.008,
    "billing_metadata": {
      "filename": "audio.wav",
      "duration_seconds": 120.5,
      "num_segments": 25,
      "unique_speakers": 3,
      "processing_mode": "background"
    }
  }
}

Cancel Transcription Task

Cancel Processing Task
DELETE https://api.mayorsoftware.ch/v1/transcribe/cancel/{task_id}

Cancel a queued or processing transcription task.

Response Format

{
  "message": "Task cancelled successfully",
  "task_id": "550e8400-e29b-41d4-a716-446655440000"
}

Statistiques Détaillées Detailed Statistics Detaillierte Statistiken Statistiche Dettagliate

Obtenir les statistiques de connexion Get connection statistics Verbindungsstatistiken abrufen Ottieni statistiche di connessione
GET /stats

Endpoint de monitoring détaillé qui retourne les connexions actives par token et les limites de rate limiting. Utile pour le debugging et l'analyse de l'utilisation du service. Detailed monitoring endpoint that returns active connections per token and rate limiting thresholds. Useful for debugging and service usage analysis. Detaillierter Überwachungsendpunkt, der aktive Verbindungen pro Token und Rate-Limiting-Schwellenwerte zurückgibt. Nützlich für Debugging und Nutzungsanalyse des Dienstes. Endpoint di monitoraggio dettagliato che restituisce connessioni attive per token e soglie di rate limiting. Utile per il debugging e l'analisi dell'utilizzo del servizio.

Réponse Succès (200 OK) Success Response (200 OK) Erfolgreiche Antwort (200 OK) Risposta di Successo (200 OK)

{
  "active_connections_per_token": {
    "abc123...": 2,
    "def456...": 1
  },
  "total_active_connections": 3,
  "rate_limits": {
    "max_concurrent_per_token": 3,
    "max_per_minute_per_token": 10
  }
}

Description des Champs Field Descriptions Feldbeschreibungen Descrizioni dei Campi

Champ Field Feld Campo Type Type Typ Tipo Description Description Beschreibung Descrizione
active_connections_per_token object Mapping token → nombre de connexions actives Mapping token → number of active connections Zuordnung Token → Anzahl aktiver Verbindungen Mappa token → numero di connessioni attive
total_active_connections integer Nombre total de connexions actives (tous tokens) Total number of active connections (all tokens) Gesamtzahl aktiver Verbindungen (alle Tokens) Numero totale di connessioni attive (tutti i token)
rate_limits object Configuration des limites de rate limiting Rate limiting configuration Rate-Limiting-Konfiguration Configurazione del rate limiting
max_concurrent_per_token integer Maximum de connexions simultanées par token (3) Maximum concurrent connections per token (3) Maximale gleichzeitige Verbindungen pro Token (3) Massimo connessioni simultanee per token (3)
max_per_minute_per_token integer Maximum de nouvelles connexions par minute par token (10) Maximum new connections per minute per token (10) Maximale neue Verbindungen pro Minute pro Token (10) Massimo nuove connessioni al minuto per token (10)

Rate Limiting Rate Limiting Rate-Limiting Rate Limiting

Le service applique des limites strictes pour éviter la surcharge: The service applies strict limits to prevent overload: Der Dienst wendet strenge Limits an, um Überlastung zu vermeiden: Il servizio applica limiti rigorosi per prevenire il sovraccarico:

  • 3 connexions simultanées maximum par token API Maximum 3 simultaneous connections per API token Maximal 3 gleichzeitige Verbindungen pro API-Token Massimo 3 connessioni simultanee per token API
  • 10 nouvelles connexions maximum par minute par token Maximum 10 new connections per minute per token Maximal 10 neue Verbindungen pro Minute pro Token Massimo 10 nuove connessioni al minuto per token
  • Code d'erreur WebSocket 1008 si les limites sont dépassées WebSocket error code 1008 if limits are exceeded WebSocket-Fehlercode 1008 bei Überschreitung der Limits Codice errore WebSocket 1008 se i limiti vengono superati

LLM Chat Completion

Generate Text with Language Models
POST https://api.mayorsoftware.ch/v1/llm/chat/completions

Chat completion endpoint powered by Qwen3 and other models. Supports streaming and non-streaming responses.

Request Parameters

Parameter Type Required Description
messages array required Array of message objects with role and content
model string optional Model name: "qwen3" (default)
profile_type string optional Response style: "standard" (default), "creative", or "precise"
temperature float optional Randomness (0.0-2.0, default: 1.0)
max_tokens integer optional Maximum response tokens (omit for unlimited)
stream boolean optional Enable streaming response (default: false)

Request Format

{
  "messages": [
    {
      "role": "system",
      "content": "You are a helpful assistant."
    },
    {
      "role": "user",
      "content": "Summarize this meeting transcript..."
    }
  ],
  "model": "qwen3",
  "profile_type": "standard",
  "temperature": 1.0,
  "max_tokens": 2048,
  "stream": false
}

Response Format

{
  "id": "chatcmpl-7890123456",
  "model": "qwen3",
  "choices": [
    {
      "message": {
        "role": "assistant",
        "content": "Generated response text..."
      },
      "finish_reason": "stop"
    }
  ],
  "usage": {
    "prompt_tokens": 45,
    "completion_tokens": 123,
    "total_tokens": 168
  }
}

JavaScript Example (Non-Streaming)

const generateResponse = async (messages) => {
  try {
    const response = await fetch('https://api.mayorsoftware.ch/v1/llm/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer epv_your_token_here',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        messages: messages,
        model: 'qwen3',
        profile_type: 'standard',
        temperature: 1.0,
        stream: false
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const result = await response.json();
    return result.choices[0].message.content;

  } catch (error) {
    console.error('LLM request failed:', error);
    return null;
  }
};

// Usage
const messages = [
  { role: 'system', content: 'You are a helpful assistant.' },
  { role: 'user', content: 'Write a short story about AI.' }
];
const response = await generateResponse(messages);
console.log(response);

JavaScript Example (Streaming)

const streamResponse = async (messages) => {
  try {
    const response = await fetch('https://api.mayorsoftware.ch/v1/llm/chat/completions', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer epv_your_token_here',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        messages: messages,
        model: 'qwen3',
        profile_type: 'standard',
        temperature: 1.0,
        stream: true
      })
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    let buffer = '';
    let fullText = '';

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value, { stream: true });
      buffer += chunk;
      const lines = buffer.split('\n');
      buffer = lines.pop() || '';

      for (const line of lines) {
        if (line.startsWith('data: ') && !line.includes('[DONE]')) {
          try {
            const data = JSON.parse(line.slice(6));
            if (data.choices && data.choices[0].delta.content) {
              const content = data.choices[0].delta.content;
              fullText += content;
              console.log(content); // Display token by token
            }
          } catch (e) {
            // Ignore parsing errors
          }
        }
      }
    }

    return fullText;

  } catch (error) {
    console.error('Streaming failed:', error);
    return null;
  }
};

Token Usage

Get Usage Statistics
GET https://api.mayorsoftware.ch/v1/token-balance/usage

Retrieve current token usage and billing information for your account. Supports both JWT and API token authentication.

Authentication

This endpoint accepts both JWT tokens and API tokens:

// Using JWT token (from user login)
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

// OR using API token
Authorization: Bearer epv_1a2b3c4d5e6f7g8h9i0j...

Query Parameters

Parameter Type Required Description
limit number optional Number of history records to return (default: 50)
offset number optional Pagination offset (default: 0)
service_type string optional Filter by service type: "transcription", "llm", "whisper", "openai"
start_date string optional Start date filter (ISO 8601 format)
end_date string optional End date filter (ISO 8601 format)
type string optional Transaction type filter: "deduction", "addition", "refund"

Response Format

{
  "current_period": {
    "start_date": "2025-11-01T00:00:00.000Z",
    "end_date": "2025-11-30T23:59:59.999Z",
    "transcription_minutes": 45.3,
    "llm_tokens": 12450,
    "cost": 23.75
  },
  "limits": {
    "transcription_minutes_limit": 100,
    "llm_tokens_limit": 50000,
    "plan": "professional"
  },
  "usage_history": [
    {
      "date": "2025-11-07",
      "transcription_minutes": 5.2,
      "llm_tokens": 850,
      "requests": 3
    }
  ],
  "transactions": [
    {
      "_id": "673...",
      "userId": "672...",
      "tokenId": "673...",
      "type": "deduction",
      "amount": 520,
      "serviceType": "transcription",
      "createdAt": "2025-11-07T14:23:45.000Z",
      "usageMetrics": {
        "duration": 5.2,
        "diarization": true
      }
    }
  ],
  "total": 125,
  "limit": 50,
  "offset": 0,
  "hasMore": true
}

JavaScript Example

const getUsageStats = async (apiToken) => {
  try {
    // Build query parameters
    const params = new URLSearchParams({
      limit: '30',  // Get last 30 days
      service_type: 'transcription'  // Filter for transcription only
    });

    const response = await fetch(`https://api.mayorsoftware.ch/v1/token-balance/usage?${params}`, {
      headers: {
        'Authorization': `Bearer ${apiToken}`  // Works with JWT or API token
      }
    });

    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }

    const usage = await response.json();
    
    console.log('Current Period Usage:');
    console.log(`Transcription: ${usage.current_period.transcription_minutes} minutes`);
    console.log(`LLM Tokens: ${usage.current_period.llm_tokens}`);
    console.log(`Cost: $${usage.current_period.cost}`);
    
    console.log(`\nTotal transactions: ${usage.total}`);
    console.log(`Showing ${usage.transactions.length} transactions`);
    
    // Display usage history
    usage.usage_history.forEach(day => {
      console.log(`${day.date}: ${day.requests} requests, ${day.transcription_minutes.toFixed(2)} min`);
    });
    
    return usage;

  } catch (error) {
    console.error('Failed to fetch usage:', error);
    return null;
  }
};

// Check usage with date range filter
const getUsageByDateRange = async (apiToken, startDate, endDate) => {
  const params = new URLSearchParams({
    start_date: startDate,  // e.g., '2025-11-01'
    end_date: endDate,      // e.g., '2025-11-30'
    limit: '100'
  });

  const response = await fetch(`https://api.mayorsoftware.ch/v1/token-balance/usage?${params}`, {
    headers: {
      'Authorization': `Bearer ${apiToken}`
    }
  });

  return response.json();
};

// Monitor usage and warn if approaching limits
getUsageStats('epv_your_token_here').then(usage => {
  if (usage) {
    const transcriptionUsagePercent = 
      (usage.current_period.transcription_minutes / usage.limits.transcription_minutes_limit) * 100;
    
    if (transcriptionUsagePercent > 80) {
      console.warn('WARNING: High transcription usage! Consider upgrading your plan.');
    }
    
    if (usage.hasMore) {
      console.log('More transactions available. Use offset parameter for pagination.');
    }
  }
});

Python Example

import requests
from datetime import datetime, timedelta

def get_usage_stats(api_token, limit=50, service_type=None):
    """Get token usage statistics with optional filtering."""
    url = 'https://api.mayorsoftware.ch/v1/token-balance/usage'
    
    headers = {
        'Authorization': f'Bearer {api_token}'
    }
    
    params = {
        'limit': limit
    }
    
    if service_type:
        params['service_type'] = service_type
    
    try:
        response = requests.get(url, headers=headers, params=params)
        response.raise_for_status()
        
        usage = response.json()
        
        print(f"Current Period Usage:")
        print(f"  Transcription: {usage['current_period']['transcription_minutes']} minutes")
        print(f"  LLM Tokens: {usage['current_period']['llm_tokens']}")
        print(f"  Cost: ${usage['current_period']['cost']}")
        print(f"\nTotal transactions: {usage['total']}")
        
        # Display usage history
        for day in usage['usage_history']:
            print(f"{day['date']}: {day['requests']} requests, {day['transcription_minutes']:.2f} min")
        
        return usage
        
    except requests.exceptions.RequestException as e:
        print(f"Error: {e}")
        return None

def get_usage_by_date_range(api_token, start_date, end_date):
    """Get usage statistics for a specific date range."""
    url = 'https://api.mayorsoftware.ch/v1/token-balance/usage'
    
    headers = {
        'Authorization': f'Bearer {api_token}'
    }
    
    params = {
        'start_date': start_date.isoformat(),
        'end_date': end_date.isoformat(),
        'limit': 100
    }
    
    response = requests.get(url, headers=headers, params=params)
    response.raise_for_status()
    return response.json()

# Usage examples
if __name__ == '__main__':
    api_token = 'epv_your_token_here'
    
    # Get overall usage
    usage = get_usage_stats(api_token)
    
    # Get only transcription usage
    transcription_usage = get_usage_stats(api_token, service_type='transcription')
    
    # Get usage for last 7 days
    end_date = datetime.now()
    start_date = end_date - timedelta(days=7)
    weekly_usage = get_usage_by_date_range(api_token, start_date, end_date)
    
    # Check if approaching limits
    if usage:
        transcription_percent = (
            usage['current_period']['transcription_minutes'] / 
            usage['limits']['transcription_minutes_limit'] * 100
        )
        
        if transcription_percent > 80:
            print('WARNING: High transcription usage!')