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.
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.
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.
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.
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
Transcription WebSocket en Temps Réel WebSocket Live-Transkription Trascrizione WebSocket in Tempo Reale
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
-
Connexion WebSocket
wss://api.mayorsoftware.ch/v1/asr?token=epv_xxx&enable_diarization=true
-
Message de configuration du serveur (Server →
Client)
Le serveur envoie immédiatement après la connexion :
{ "type": "config", "useAudioWorklet": false } -
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": [] -
Accusé de réception des signatures (Server →
Client)
Le serveur confirme la réception :
{ "type": "config_ack", "signatures_received": 2 } -
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
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
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
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
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
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
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
/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
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
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!')