
Webhooks vs polling para transcripciones: la elección asíncrona
Summarize this article with:
Usa polling cuando tienes menos de 50 trabajos al día o un usuario está mirando activamente una barra de progreso. Cambia a webhooks cuando el volumen supera aproximadamente los 100 trabajos al día, cuando los trabajos se ejecutan en segundo plano o cuando los resultados deben distribuirse a varios destinos. La matemática es clara: con 200 trabajos al día, los webhooks reducen las llamadas a la API en 18 veces. Lo complicado es hacerlo de forma segura: verificación HMAC, idempotencia y saber qué proveedores ofrecen realmente un mecanismo de callback.
Usa polling cuando tienes menos de 50 trabajos al día o un usuario está esperando activamente. Cambia a webhooks por encima de unos 100 trabajos al día cuando los trabajos se ejecutan en segundo plano. Esa es la decisión en dos frases. Todo lo que viene abajo son los detalles de implementación que marcan la diferencia entre un webhook que funciona y uno que pierde transcripciones en silencio a las 2 de la madrugada.
El cálculo de recursos
Un ejemplo concreto. Transcribes 200 trabajos al día. Cada uno tarda 3 minutos de media.
Polling cada 5 segundos:
- Cada trabajo: 36 peticiones de polling de media (3 min x 12 polls/min)
- Al día: 7.200 peticiones de polling
- Resultados útiles en esas peticiones: aproximadamente el 1%
Webhooks:
- Cada trabajo: 1 envío + 1 entrega de webhook
- Al día: 200 envíos + 200 webhooks = 400 eventos
- El 100% de los eventos lleva un resultado
Con este volumen, los webhooks son 18 veces más eficientes. Con 2.000 trabajos al día, el polling se vuelve genuinamente caro para ambos lados de la API, y la mayoría de los proveedores empiezan a limitarte la tasa en las comprobaciones de estado antes que en los envíos.
Cuándo el polling sigue siendo la opción correcta
No tienes un endpoint HTTP público. Los entornos de desarrollo local, las apps mobile-first sin backend y las herramientas internas detrás de una VPN no pueden recibir entregas de webhooks. El polling solo requiere HTTP saliente.
El volumen es menor de 50 trabajos al día. El costo de recursos es insignificante. La simplicidad de un bucle de polling pesa más que la infraestructura de un receptor de webhooks.
El usuario está mirando activamente. Un usuario subió una entrevista y está pendiente de la barra de progreso. El polling te da algo con qué actualizar la UI. Los webhooks exigirían mecanismos adicionales (WebSocket, eventos enviados por el servidor o un servicio push) para llevar la señal de finalización de vuelta al navegador. Consulta construir con APIs de transcripción para ver un bucle de polling funcional.
Cuándo cambiar a webhooks
Tres señales:
El volumen supera la marca de 100 trabajos al día. El costo de infraestructura de un receptor de webhooks se paga solo con el ahorro en llamadas a la API en cuestión de una semana.
La latencia no importa porque el usuario no está mirando. Procesamiento en segundo plano de grabaciones que van a parar a una base de datos para consultarse después. El usuario verá el resultado la próxima vez que abra el panel.
Los resultados necesitan distribuirse a varios destinos. Un webhook puede disparar la escritura en tu base de datos, una notificación de Slack y una actualización de HubSpot simultáneamente. El polling tiene que hacer esto de forma serial en el código de tu aplicación. Consulta integrar transcripción con Slack, Notion o HubSpot para las recetas de distribución.
Qué APIs de transcripción realmente soportan webhooks
Esto varía más de lo que la documentación da a entender.
| Proveedor | Mecanismo asíncrono | Parámetro de entrega | Verificación de firma | Reintentos |
|---|---|---|---|---|
| AssemblyAI | Webhook (POST) | webhook_url en el cuerpo | Cabecera personalizada (configuras tú el nombre + valor) | 10 intentos, 10 s entre cada uno |
| Deepgram | Callback (POST) | parámetro callback en la query | cabecera dg-token (identificador de la clave de API) | 10 intentos, 30 s entre cada uno |
| Rev.ai | Webhook (POST) | objeto notification_config | cabecera de autenticación vía config | cada 30 min durante hasta 24 h |
| AWS Transcribe | Solo polling | GetTranscriptionJob | N/D | N/D |
| Google Cloud STT | Solo polling (operación de larga duración) | Operations.get | N/D | N/D |
| OpenAI Whisper | Solo síncrono | N/D | N/D | N/D |
AWS Transcribe no tiene entrega por webhook en absoluto. Envías un trabajo y luego haces polling de GetTranscriptionJob hasta que TranscriptionJobStatus sea igual a COMPLETED. El LongRunningRecognize de Google Cloud Speech-to-Text devuelve un identificador de operación que consultas con Operations.get hasta que done sea verdadero. El endpoint /v1/audio/transcriptions de OpenAI es completamente síncrono: te bloqueas hasta que llega la respuesta o se agota el tiempo.
Mi opinión: el mecanismo de callback de Deepgram es el más apto para producción de los tres que soportan entrega asíncrona. El payload de AssemblyAI entrega solo un transcript_id y un campo status al completarse, lo que significa que siempre necesitas una segunda llamada a la API para obtener la transcripción real. Deepgram envía el resultado completo a tu URL de callback.
Para un análisis más profundo de cómo las principales APIs cobran su uso, consulta precios de APIs de voz a texto 2026.
Configurar un webhook (API de ConvertAudioToText)
La llamada de registro:
curl -X POST https://api.convertaudiototext.com/api/v1/dashboard/webhooks \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/transcription",
"events": ["job.completed", "job.failed"]
}'
La respuesta incluye un campo secret. Guárdalo. La API genera el secreto del lado del servidor y lo devuelve una sola vez en el momento de la creación. No se almacena en forma recuperable.
Eventos disponibles: job.queued, job.processing, job.completed, job.failed. La mayoría de las integraciones se suscriben solo a job.completed y job.failed.

Validación de la firma HMAC
Cada entrega incluye una cabecera X-Webhook-Signature con el formato de valor sha256=<hex>. La firma es HMAC-SHA256(secret, raw_body).
En Node:
import crypto from 'crypto';
import express from 'express';
const app = express();
app.post('/webhooks/transcription',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.header('X-Webhook-Signature');
const expected = 'sha256=' + crypto
.createHmac('sha256', process.env.WEBHOOK_SECRET)
.update(req.body)
.digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(req.body.toString());
handleTranscript(event);
res.sendStatus(200);
}
);
En Python:
import hmac
import hashlib
def verify(signature: str, body: bytes, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(),
body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
Usa timingSafeEqual (Node) o hmac.compare_digest (Python). Una comparación de cadenas ingenua filtra información a través del tiempo de respuesta.
Analiza el cuerpo después de validar, nunca antes. Un middleware que parsea el JSON antes de que se ejecute tu handler consumirá los bytes crudos, haciendo imposible el cálculo de la firma. El ejemplo con express.raw() de arriba es deliberado: primero obtienes el buffer crudo y luego parseas.
Idempotencia
El worker de entregas puede dispararse más de una vez para el mismo evento. Las redes fallan. Tu handler puede procesar un evento y fallar antes de devolver un 200. El proveedor reintenta. Tu handler se ejecuta otra vez.
Cada evento tiene un event_id único (disponible en el payload). El patrón seguro:
async function handleTranscript(event) {
const inserted = await db.query(
`INSERT INTO processed_events (event_id) VALUES ($1)
ON CONFLICT DO NOTHING RETURNING id`,
[event.data.job_id + ':' + event.event]
);
if (inserted.rowCount === 0) return;
await saveTranscript(event.data.job_id, event.data.result_url);
}
ON CONFLICT DO NOTHING significa que las entregas duplicadas salen silenciosamente. Gana la primera entrega; los duplicados se ignoran sin lanzar errores.
Comportamiento de los reintentos
El worker de entregas de ConvertAudioToText reintenta las entregas fallidas según este calendario (5 intentos en total):
| Intento | Retraso |
|---|---|
| 1 | Inmediato |
| 2 | 1 minuto |
| 3 | 5 minutos |
| 4 | 15 minutos |
| 5 | 1 hora |
| 6 | 6 horas |
Después de 5 intentos fallidos, la entrega se marca como failed. Puedes ver el historial de entregas y disparar reintentos manuales desde el panel de webhooks, o usar el endpoint de reintento:
curl -X POST https://api.convertaudiototext.com/api/v1/dashboard/webhooks/deliveries/{delivery_id}/retry \
-H "Authorization: Bearer $API_KEY"
Para que tu handler se comporte correctamente: devuelve 2xx para éxito, 4xx para fallos permanentes (sin reintento necesario), 5xx para fallos transitorios (reintento deseado). Responde en menos de 30 segundos. Si tu procesamiento es lento, confirma de inmediato y encola el trabajo real:
app.post('/webhooks/transcription', (req, res) => {
validateSignature(req);
jobQueue.push(req.body);
res.sendStatus(200); // ack first, process after
});
Desarrollo local
Los webhooks requieren una URL HTTPS pública. Dos enfoques que funcionan:
Túnel con ngrok o cloudflared. Expone tu servidor local a internet con una URL temporal.
ngrok http 3000
# Use the resulting https URL as your webhook URL
Handler de doble modo. Webhooks en producción, polling en desarrollo local. Una variable de entorno cambia el comportamiento. Esto mantiene simple el bucle de retroalimentación local sin tocar el código de producción.
Patrones de producción
Directo a base de datos. El handler escribe la transcripción en Postgres o MongoDB y devuelve un 200. El código posterior consulta la base de datos. El patrón más simple, funciona a cualquier escala.
Integración directa. El handler publica en Slack, crea una página de Notion o actualiza un contacto de HubSpot. Buena opción cuando la integración es el destino principal. Falla de forma ruidosa (5xx) si el sistema posterior está caído, lo que dispara reintentos automáticamente.
Bus de eventos. El handler publica en Kafka, SNS o un tema interno de pub/sub. Varios consumidores procesan el mismo evento de forma independiente. Desacopla la recepción del webhook del procesamiento posterior. El patrón correcto para pipelines grandes donde varios sistemas consumen la misma transcripción. Consulta transcripción por lotes para proyectos grandes para conocer la arquitectura del pipeline.
Mezclar ambos patrones
A veces quieres ambos. El usuario sube un archivo. Tu backend envía el trabajo y empieza a hacer polling para las actualizaciones de la UI. El webhook se dispara al terminar y se convierte en el registro canónico en tu base de datos. El usuario recibe retroalimentación inmediata; el backend obtiene una señal asíncrona fiable que no depende de que la UI siga abierta.
Este enfoque dual requiere más código pero ofrece la mejor experiencia de usuario cuando los usuarios esperan activamente los resultados de archivos que les importan, mientras el sistema también gestiona los trabajos en segundo plano de forma fiable.
Si solo necesitas transcripciones limpias sin construir una integración de backend, ConvertAudioToText gestiona todo el pipeline en el navegador sin necesidad de clave de API.
FAQ
¿Cuándo debería usar polling en lugar de webhooks para transcripción?
Usa polling cuando no tienes un endpoint HTTP público (desarrollo local, herramientas solo accesibles por VPN, apps móviles sin backend), cuando el volumen es menor de 50 trabajos al día, o cuando un usuario está esperando activamente y necesitas actualizar una barra de progreso en tiempo real. Los webhooks añaden un costo de infraestructura que el polling no justifica con poco volumen.
¿Qué APIs de transcripción importantes soportan webhooks?
AssemblyAI soporta webhooks mediante un parámetro webhook_url (10 intentos de reintento, timeout de 10 segundos). Deepgram soporta un parámetro callback en la query con verificación mediante la cabecera dg-token y 10 reintentos cada 30 segundos. Rev.ai usa un objeto notification_config con hasta 24 horas de reintentos. AWS Transcribe y Google Cloud Speech-to-Text requieren polling: AWS vía GetTranscriptionJob y Google vía la interfaz de operación de larga duración Operations.get. OpenAI Whisper es completamente síncrono, sin ningún tipo de entrega asíncrona.
¿Cómo valido que un webhook proviene de la fuente correcta?
El patrón estándar es HMAC-SHA256: el proveedor firma el cuerpo crudo de la petición con tu secreto compartido y pone el resultado en una cabecera. Tu handler recalcula el mismo HMAC y compara usando una función de igualdad segura en tiempo. Nunca uses una comparación de cadenas simple, que filtra información a través del timing. Deepgram usa un mecanismo distinto (una cabecera dg-token vinculada a tu clave de API), así que el enfoque varía según el proveedor.
¿Qué debe devolver mi handler de webhook y con qué rapidez?
Devuelve un código de estado 2xx para confirmar la recepción, y hazlo dentro de la ventana de timeout de tu proveedor (30 segundos es lo habitual). Si tu procesamiento real es costoso, confirma de inmediato y encola el trabajo. Devuelve 5xx para los fallos transitorios que quieres que se reintenten y 4xx para los fallos permanentes que no. Las respuestas lentas provocan tormentas de reintentos que pueden saturar tu cola de entregas.
Fuentes
- Documentación de webhooks de AssemblyAI: https://www.assemblyai.com/docs/getting-started/webhooks (consultado el 2026-07-02)
- Documentación de callbacks de Deepgram: https://developers.deepgram.com/docs/callback (consultado el 2026-07-02)
- Documentación de webhooks de Rev.ai: https://docs.rev.ai/api/asynchronous/webhooks/ (consultado el 2026-07-02)
- AWS Transcribe GetTranscriptionJob: https://docs.aws.amazon.com/transcribe/latest/APIReference/API_GetTranscriptionJob.html (consultado el 2026-07-02)
- Google Cloud STT LongRunningRecognize: https://cloud.google.com/speech-to-text/docs/reference/rest/v1/speech/longrunningrecognize (consultado el 2026-07-02)
- API de voz a texto de OpenAI: https://developers.openai.com/api/docs/guides/speech-to-text (consultado el 2026-07-02)
Try transcription free
Convert any audio or video to clean, unwatermarked text — speaker labels, timestamps, and AI summaries included. First 10 minutes free, no account.
Related Articles

Speechmatics Alternative for Non-Developers: Web Transcription Without Code
Speechmatics is genuinely excellent for developers: 50 hours free per month, 56 languages, on-prem deployment. If you need a drag-and-drop web app with flat $9.99/mo pricing instead of an API, here is an honest comparison of the two.

Best Transcription Tools with API Access (2026)
Which transcription SaaS tools actually give you API keys, and on which plan? Verified pricing and plan gates for Descript, Sonix, Fireflies, Happy Scribe, AssemblyAI, and more.