Gladia, Deepgram, AssemblyAI, Speechmatics, Soniox y ElevenLabs, seleccionados por bot, con su propia API key, su propia región y paso directo de todas las opciones específicas de cada proveedor.

Elegir un proveedor de speech-to-text no es una decisión que se tome una sola vez. La precisión en su dominio, el precio por hora, los idiomas que necesita, si el proveedor firmará un DPA con los datos permaneciendo en la UE, y qué tan bien aguanta la diarización cuando tres personas hablan encima, todo eso cambia, y nada de eso tiene la misma respuesta para cada cliente.
Así que dejamos de elegir. Usted elige el proveedor por bot, y puede cambiar de opinión sobre una grabación que ya tiene.
Entre qué puede elegir
| Proveedor | Por lotes | En vivo |
|---|---|---|
gladia | ✅ | ✅ |
deepgram | ✅ | ✅ |
assemblyai | ✅ | ✅ |
speechmatics | ✅ | ✅ |
soniox | ✅ | ✅ |
elevenlabs | — | ✅ |
ElevenLabs es solo streaming. Los otros cinco hacen ambas cosas.
El modo por lotes (batch) es lo que quiere la mayoría: la reunión termina, se envía el audio, un webhook devuelve la transcripción con etiquetas de hablante y tiempos a nivel de palabra. En vivo (live) significa segmentos de transcripción que llegan por un WebSocket mientras la reunión sigue en curso, para cualquier cosa que tenga que reaccionar dentro de la sala.
Se configuran de forma independiente, y puede ejecutar ambos en el mismo bot con proveedores distintos si quiere un feed en vivo rápido y una transcripción final más precisa.
Por lotes
{
"meeting_url": "https://meet.google.com/abc-defg-hij",
"bot_name": "Recording Bot",
"transcription_enabled": true,
"transcription_config": {
"provider": "speechmatics",
"region": "eu2",
"api_key": null,
"custom_params": null
}
}Cuatro campos. provider toma el valor "gladia" por defecto si lo omite. region, api_key y custom_params son null por defecto y se cubren más abajo.
transcription_config es obligatorio cuando transcription_enabled es true, y se ignora cuando es false.

Una vez que el bot termina, transcription_provider y transcription_ids vuelven en el registro del bot y en el payload del webhook, y GET /v2/bots/:bot_id/status informa en vivo el transcription_status consultado al propio proveedor: not-applicable, not-started, queued, processing, done o error.
Fijar la región
La mayoría de estos proveedores se ejecuta en más de una región, y para muchos de nuestros clientes ahí se juega todo.
| Proveedor | Regiones por lotes | Regiones en vivo |
|---|---|---|
gladia | solo endpoint global | us-west, eu-west |
deepgram | global, eu | global, eu |
assemblyai | us, eu | us, eu |
speechmatics | eu1, eu2, us1, us2, au1 | las mismas |
soniox | us, eu, jp | las mismas |
elevenlabs | — | global, us, eu, in |
Envíe una región que el proveedor no tenga y recibe un 400 al crear el bot con los valores permitidos listados, en lugar de una sorpresa más adelante. La API por lotes de Gladia es solo global, y por eso se rechaza pasar region con provider: "gladia" en la configuración por lotes. Su API en vivo sí tiene regiones.
Deje region en null y elegimos un valor predeterminado sensato: eu para Deepgram y AssemblyAI, eu1 para Speechmatics, us para Soniox.
Si necesita que el audio nunca salga de una jurisdicción, combine esto con traiga su propio almacenamiento. Los proveedores obtienen el audio desde una URL firmada del bucket, así que la ubicación del bucket y la región del proveedor determinan juntas a dónde va realmente el audio.
Traiga su propia clave
Pase api_key y usamos su cuenta con ese proveedor en lugar de la nuestra.
{
"transcription_config": {
"provider": "deepgram",
"region": "eu",
"api_key": "your-deepgram-key"
}
}Las claves se cifran con AES-256-GCM antes de almacenarse y siguen cifradas en tránsito hacia el bot, que descifra en el punto de uso. Cuando elimina los datos de un bot, la clave almacenada se sobrescribe.
Hay dos razones para usarlo. La primera es el costo: la transcripción con nuestra clave se factura a 0,25 tokens por hora; con la suya, a 0,05. La segunda es que algunas cosas solo son posibles en su propia cuenta, como un vocabulario personalizado que haya entrenado o un contrato con condiciones que nosotros no tenemos.
BYOK está disponible en los planes Pro y superiores. Sin él obtiene FST_ERR_BYOK_TRANSCRIPTION_NOT_ENABLED_ON_PLAN.
Opciones del proveedor, pasadas tal cual
Deliberadamente no construimos una capa de opciones normalizada. Cada proveedor tiene funciones que los demás no tienen, y aplanarlas a un denominador común significaría tirar a la basura la razón por la que eligió ese proveedor.
custom_params va al proveedor más o menos tal como usted lo escribió:
{
"transcription_config": {
"provider": "speechmatics",
"region": "eu2",
"custom_params": {
"transcription_config": {
"language": "en",
"diarization": "speaker",
"operating_point": "enhanced"
}
}
}
}La notación de punto también funciona, si le resulta más fácil de construir:
{ "custom_params": { "diarization_config.min_speakers": 2 } }En la configuración en vivo se desaplana antes de validar, así que valida la forma que el proveedor va a recibir realmente. En la configuración por lotes la clave plana se valida tal como está escrita y se desaplana después, al momento del envío.
En la configuración en vivo, hay cuatro campos que establece el pipeline y que se rechazan si los envía: encoding, sample_rate, bit_depth, channels. La frecuencia de muestreo en particular se negocia por proveedor a partir del audio de la reunión, así que sobrescribirla rompería el stream. Use streaming_config.audio_frequency en su lugar.
La diarización está activada por defecto, porque sin ella obtiene un muro de texto sin etiquetas de hablante, y al menos un proveedor devuelve en silencio cero utterances si no la pide. Un valor explícito en custom_params tiene prioridad.
La trampa: por lotes y en vivo aceptan formas distintas
Esto es lo que le cuesta una tarde a la gente, así que vale la pena decirlo sin rodeos. Para el mismo proveedor, la API en vivo y la API por lotes no aceptan la misma forma de parámetros.
Gladia es el ejemplo más claro. La versión por lotes recibe la configuración de traducción en el nivel superior. La versión en vivo la quiere anidada bajo realtime_processing:
{
"streaming_config": {
"mode": "transcription",
"output_url": "wss://your-app.example.com/transcripts",
"audio_frequency": 24000,
"transcription": {
"provider": "gladia",
"region": "eu-west",
"api_key": "your-gladia-key",
"custom_params": {
"language_config": { "languages": ["ru"] },
"realtime_processing": {
"translation": true,
"translation_config": { "target_languages": ["en"] }
}
}
}
}
}Los parámetros en vivo se validan en modo estricto, porque las API de sesión en vivo rechazan de plano las claves desconocidas y preferimos fallar al crear su bot antes que fallar en su reunión. Cuando envía una clave que va un nivel más abajo, el error le dice a dónde va:
'translation' is not a top-level field of the gladia live API —
did you mean 'realtime_processing.translation'?
(the live API shape differs from batch)Tanto los parámetros por lotes como los en vivo se comprueban contra el esquema propio de cada proveedor al crear el bot, así que un error de tipeo vuelve como un 400 en un segundo en lugar de como una transcripción fallida una hora más tarde. Dos matices sobre qué tan estricto es eso. El parseo por lotes es permisivo, así que una clave por lotes desconocida pasa la validación y se reenvía para que el proveedor la resuelva; solo el modo en vivo rechaza claves desconocidas. Y los parámetros en vivo de ElevenLabs se pasan sin validación, porque no hay un esquema publicado contra el cual comprobarlos.
Salida en vivo
Con mode: "transcription", abrimos la sesión del proveedor, le alimentamos el audio de la reunión y reenviamos los eventos a su output_url como JSON:
{
"event": "transcript.segment",
"bot_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"data": {
"text": "so the migration lands Thursday",
"isFinal": true,
"utteranceStart": 12.44,
"utteranceEnd": 14.91,
"confidence": 0.97,
"speaker": { "name": "Alice", "id": 1 },
"words": []
}
}También session.started con el proveedor que se usó, translation cuando la haya pedido, y error. Hacemos ping cada 30 segundos para evitar que los intermediarios cierren un socket inactivo.
Una restricción: las sesiones en vivo con nuestra clave de plataforma están limitadas a un conjunto gestionado de proveedores, actualmente Gladia. Cualquier otro proveedor para transcripción en vivo necesita una clave BYOK, y lo rechazamos al crear el bot con FST_ERR_STREAMING_TRANSCRIPTION_KEY_UNAVAILABLE en lugar de descubrirlo cuando arranca la reunión.
Cambiar de opinión
POST /v2/bots/:bot_id/retranscribe{
"transcription": {
"provider": "assemblyai",
"region": "eu",
"api_key": "your-assemblyai-key"
}
}El audio almacenado se reenvía a otro proveedor y se actualiza la configuración del bot. Así es como se hace un A/B entre dos proveedores con sus propias reuniones en lugar de con el audio de demo de ellos, y así es como se recupera una transcripción que falló.
Eliminar los datos de un bot también saca la transcripción del proveedor, con ?delete_from_provider=true (el valor predeterminado), usando su propia clave allí donde usted la haya proporcionado.
Qué pasa cuando un proveedor tiene un mal día
Un envío fallido se reintenta dos veces, a los 5 y a los 15 segundos, para un total de tres intentos. Solo son elegibles los errores en los que un reintento podría plausiblemente funcionar: límites de tasa, 5xx, timeouts de conexión y de polling, fallos a nivel de red, y el caso en que el proveedor devolvió un 2xx con un cuerpo sin ningún id de trabajo. Los errores de autenticación, la entrada inválida y las operaciones no soportadas no se reintentan nunca, porque fallarían igual la segunda vez.
Cada reintento rota el secreto del callback antes de reenviar. Eso cierra una carrera real: si el proveedor realmente aceptó un trabajo cuya respuesta expiró de nuestro lado, su callback llega contra un secreto que ya no existe y se rechaza, en lugar de competir con el trabajo reintentado y producir dos transcripciones para un mismo fragmento.
No hay failover automático a un segundo proveedor, y prefiero decirlo con todas las letras antes que dejar que lo descubra durante un incidente. Si el proveedor que eligió falla tras los reintentos, el bot termina en failed con TRANSCRIPTION_FAILED, y la grabación y los artefactos de audio siguen todos ahí. La recuperación es una llamada a retranscribe, indicando opcionalmente un proveedor distinto. Cambiar de proveedor en silencio significaría una transcripción en una jurisdicción que usted no aceptó, a un precio que usted no aceptó, así que es una decisión que dejamos en sus manos.
Relacionado
- Traiga su propio almacenamiento — controle dónde vive realmente el audio que lee el proveedor
- Referencia de la API de Meeting BaaS