
Webhooks vs Polling para Transcrições: A Escolha Assíncrona
Summarize this article with:
Use polling quando você tiver menos de 50 jobs por dia ou um usuário estiver acompanhando uma barra de progresso ativamente. Migre para webhooks quando o volume passar de cerca de 100 jobs por dia, quando os jobs rodarem em segundo plano, ou quando os resultados precisarem ser distribuídos para vários destinos. A conta é clara: com 200 jobs por dia, os webhooks reduzem as chamadas de API em 18x. A parte delicada é implementá-los com segurança: verificação HMAC, idempotência e saber quais fornecedores realmente oferecem um mecanismo de callback.
Use polling quando você tiver menos de 50 jobs por dia ou um usuário estiver aguardando ativamente. Migre para webhooks acima de aproximadamente 100 jobs por dia, quando os jobs rodarem em segundo plano. Essa é a decisão em duas frases. Tudo abaixo são os detalhes de implementação que fazem a diferença entre um webhook que funciona e um que perde transcrições silenciosamente às 2 da manhã.
A Matemática dos Recursos
Um exemplo concreto. Você transcreve 200 jobs por dia. Cada um leva 3 minutos em média.
Polling a cada 5 segundos:
- Cada job: 36 requisições de polling em média (3 min x 12 polls/min)
- Por dia: 7.200 requisições de polling
- Resultados úteis nessas requisições: cerca de 1%
Webhooks:
- Cada job: 1 envio + 1 entrega de webhook
- Por dia: 200 envios + 200 webhooks = 400 eventos
- 100% dos eventos trazem um resultado
Os webhooks são 18x mais eficientes nesse volume. Com 2.000 jobs por dia, o polling se torna genuinamente caro dos dois lados da API, e a maioria dos provedores começa a impor rate limit nas verificações de status antes de impô-lo nos envios.
Quando o Polling Ainda É a Escolha Certa
Você não tem um endpoint HTTP público. Ambientes locais de desenvolvimento, apps mobile-first sem backend e ferramentas internas atrás de uma VPN não conseguem receber entregas de webhook. O polling exige apenas HTTP de saída.
O volume é inferior a 50 jobs por dia. O custo de recursos é desprezível. A simplicidade de um loop de polling supera a infraestrutura de um receptor de webhook.
O usuário está acompanhando ativamente. Um usuário enviou uma entrevista e está de olhos fixos em uma barra de progresso. O polling te dá algo com que atualizar a interface. Webhooks exigiriam infraestrutura adicional (WebSocket, server-sent events ou um serviço de push) para levar o sinal de conclusão de volta ao navegador. Veja como construir com APIs de transcrição para um loop de polling funcional.
Quando Migrar para Webhooks
Três sinais:
O volume ultrapassa a marca de 100 jobs por dia. O custo de infraestrutura de um receptor de webhook se paga em economia de chamadas de API dentro de uma semana.
A latência não importa porque o usuário não está assistindo. Processamento em segundo plano de gravações que vão parar em um banco de dados para consulta posterior. O usuário verá o resultado na próxima vez que abrir o painel.
Os resultados precisam ser distribuídos para vários destinos. Um webhook pode disparar a gravação no seu banco de dados, uma notificação no Slack e uma atualização no HubSpot simultaneamente. O polling precisa fazer isso serialmente no código da sua aplicação. Veja integração de transcrição com Slack, Notion ou HubSpot para as receitas de fan-out.
Quais APIs de Transcrição Realmente Suportam Webhooks
Isso varia mais do que a documentação sugere.
| Fornecedor | Mecanismo assíncrono | Parâmetro de entrega | Verificação de assinatura | Retentativas |
|---|---|---|---|---|
| AssemblyAI | Webhook (POST) | webhook_url no corpo | Cabeçalho personalizado (você configura nome + valor) | 10 tentativas, 10s entre cada |
| Deepgram | Callback (POST) | parâmetro de query callback | cabeçalho dg-token (identificador da chave de API) | 10 tentativas, 30s entre cada |
| Rev.ai | Webhook (POST) | objeto notification_config | Cabeçalho de autenticação via config | A cada 30 min por até 24 h |
| AWS Transcribe | Somente polling | GetTranscriptionJob | N/A | N/A |
| Google Cloud STT | Somente polling (operação de longa duração) | Operations.get | N/A | N/A |
| OpenAI Whisper | Somente síncrono | N/A | N/A | N/A |
O AWS Transcribe não tem entrega via webhook nenhuma. Você envia um job e depois faz polling em GetTranscriptionJob até que TranscriptionJobStatus seja igual a COMPLETED. O LongRunningRecognize do Google Cloud Speech-to-Text retorna um handle de operação que você consulta com Operations.get até que done seja verdadeiro. O endpoint /v1/audio/transcriptions da OpenAI é totalmente síncrono: você fica bloqueado até a resposta voltar ou até estourar o tempo limite.
Minha opinião: o mecanismo de callback do Deepgram é o mais amigável para produção entre os três que suportam entrega assíncrona. O payload da AssemblyAI entrega apenas um transcript_id e um campo status na conclusão, o que significa que você sempre precisa de uma segunda chamada de API para buscar a transcrição em si. O Deepgram envia o resultado completo para a sua URL de callback.
Para uma análise mais profunda de como as principais APIs precificam seu uso, veja preços de APIs de fala para texto em 2026.
Configurando um Webhook (API do ConvertAudioToText)
A chamada 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"]
}'
A resposta inclui um campo secret. Guarde-o. A API gera o secret no lado do servidor e o retorna uma única vez, no momento da criação. Ele não é armazenado de forma recuperável.
Eventos disponíveis: job.queued, job.processing, job.completed, job.failed. A maioria das integrações assina apenas job.completed e job.failed.

Validação de Assinatura HMAC
Cada entrega inclui um cabeçalho X-Webhook-Signature com o formato de valor sha256=<hex>. A assinatura é HMAC-SHA256(secret, raw_body).
Em 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);
}
);
Em 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)
Use timingSafeEqual (Node) ou hmac.compare_digest (Python). Comparação ingênua de strings vaza informações pelo tempo de resposta.
Faça o parse do corpo após validar, nunca antes. Um middleware que faça o parse do JSON antes de o seu handler executar vai consumir os bytes brutos, tornando impossível calcular a assinatura. O exemplo com express.raw() acima é proposital: você recebe primeiro o buffer bruto e só então faz o parse.
Idempotência
O worker de entrega pode disparar mais de uma vez para o mesmo evento. Redes falham. Seu handler pode processar um evento e cair antes de retornar 200. O fornecedor tenta de novo. Seu handler roda outra vez.
Cada evento tem um event_id único (disponível no payload). O padrão 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 entregas duplicadas saem silenciosamente. A primeira entrega vence; as duplicatas são ignoradas sem gerar erros.
Comportamento de Retentativas
O worker de entrega do ConvertAudioToText repete entregas que falharam neste cronograma (5 tentativas no total):
| Tentativa | Intervalo |
|---|---|
| 1 | Imediato |
| 2 | 1 minuto |
| 3 | 5 minutos |
| 4 | 15 minutos |
| 5 | 1 hora |
| 6 | 6 horas |
Após 5 tentativas malsucedidas, a entrega é marcada como failed. Você pode visualizar o histórico de entregas e disparar retentativas manuais pelo dashboard de webhooks, ou usar o endpoint de retry:
curl -X POST https://api.convertaudiototext.com/api/v1/dashboard/webhooks/deliveries/{delivery_id}/retry \
-H "Authorization: Bearer $API_KEY"
Para que o seu handler se comporte corretamente: retorne 2xx para sucesso, 4xx para falhas permanentes (retry desnecessário), 5xx para falhas transitórias (retry desejado). Responda em até 30 segundos. Se o seu processamento for lento, confirme o recebimento imediatamente e coloque o trabalho real na fila:
app.post('/webhooks/transcription', (req, res) => {
validateSignature(req);
jobQueue.push(req.body);
res.sendStatus(200); // ack first, process after
});
Desenvolvimento Local
Webhooks exigem uma URL HTTPS pública. Duas abordagens que funcionam:
Túnel ngrok ou cloudflared. Expõe o seu servidor local à internet com uma URL temporária.
ngrok http 3000
# Use the resulting https URL as your webhook URL
Handler em modo duplo. Webhooks em produção, polling no ambiente local de desenvolvimento. Uma variável de ambiente alterna o comportamento. Isso mantém o loop de feedback local simples sem alterar o código de produção.
Padrões de Produção
Direto ao banco de dados. O handler grava a transcrição no Postgres ou MongoDB e retorna 200. O código downstream consulta o banco de dados. O padrão mais simples, funciona em qualquer escala.
Integração direta. O handler publica no Slack, cria uma página no Notion ou atualiza um contato no HubSpot. Bom quando a integração é o destino principal. Falha de forma ruidosa (5xx) se o serviço downstream estiver fora do ar, o que aciona retentativas automaticamente.
Event bus. O handler publica em Kafka, SNS ou um tópico interno de pub/sub. Vários consumidores processam o mesmo evento de forma independente. Desacopla a recepção do webhook do processamento downstream. O padrão certo para pipelines grandes em que múltiplos sistemas consomem a mesma transcrição. Veja transcrição em lote para projetos grandes para a arquitetura do pipeline.
Combinando os Dois Padrões
Às vezes você quer os dois. O usuário envia um arquivo. Seu backend submete o job e começa a fazer polling para atualizações da interface. O webhook dispara ao concluir e se torna o registro canônico no seu banco de dados. O usuário recebe feedback imediato; o backend recebe um sinal assíncrono confiável que não depende da interface permanecer aberta.
Essa abordagem dupla exige mais código, mas entrega a melhor experiência de usuário quando os usuários aguardam ativamente resultados de arquivos com os quais se importam, enquanto o sistema também lida com jobs em segundo plano de forma confiável.
Se você só precisa de transcrições limpas sem construir uma integração de backend, o ConvertAudioToText cuida de todo o pipeline no navegador, sem necessidade de chave de API.
FAQ
Quando devo usar polling em vez de webhooks para transcrição?
Use polling quando você não tem um endpoint HTTP público (ambiente local de desenvolvimento, ferramentas acessíveis apenas via VPN, apps móveis sem backend), quando o volume é inferior a 50 jobs por dia, ou quando um usuário está aguardando ativamente e você precisa atualizar uma barra de progresso em tempo real. Webhooks adicionam custo de infraestrutura que o polling não justifica em volumes baixos.
Quais das principais APIs de transcrição suportam webhooks?
A AssemblyAI suporta webhooks por meio de um parâmetro webhook_url (10 tentativas de retry, timeout de 10 segundos). O Deepgram suporta um parâmetro de query callback com verificação pelo cabeçalho dg-token e 10 retentativas a cada 30 segundos. A Rev.ai usa um objeto notification_config com retentativas por até 24 horas. AWS Transcribe e Google Cloud Speech-to-Text exigem polling: AWS via GetTranscriptionJob e Google via a interface de operação de longa duração Operations.get. O OpenAI Whisper é totalmente síncrono, sem entrega assíncrona alguma.
Como validar que um webhook veio da fonte correta?
O padrão convencional é HMAC-SHA256: o provedor assina o corpo bruto da requisição com o seu segredo compartilhado e coloca o resultado em um cabeçalho. Seu handler recalcula o mesmo HMAC e compara usando uma função de igualdade segura contra ataques de timing. Nunca use uma comparação simples de strings, que vaza informações por meio do timing. O Deepgram usa um mecanismo diferente (um cabeçalho dg-token vinculado à sua chave de API), então a abordagem varia conforme o fornecedor.
O que meu handler de webhook deve retornar e com qual rapidez?
Retorne um código de status 2xx para confirmar o recebimento, e faça isso dentro da janela de tempo limite do seu fornecedor (30 segundos é o comum). Se o seu processamento real for caro, confirme imediatamente e coloque o trabalho na fila. Retorne 5xx para falhas transitórias que você quer ver repetidas, 4xx para falhas permanentes que não. Respostas lentas disparam tempestades de retentativas que podem congestionar sua fila de entrega.
Fontes
- Documentação de webhooks da AssemblyAI: https://www.assemblyai.com/docs/getting-started/webhooks (verificado em 2026-07-02)
- Documentação de callback do Deepgram: https://developers.deepgram.com/docs/callback (verificado em 2026-07-02)
- Documentação de webhooks da Rev.ai: https://docs.rev.ai/api/asynchronous/webhooks/ (verificado em 2026-07-02)
- AWS Transcribe GetTranscriptionJob: https://docs.aws.amazon.com/transcribe/latest/APIReference/API_GetTranscriptionJob.html (verificado em 2026-07-02)
- Google Cloud STT LongRunningRecognize: https://cloud.google.com/speech-to-text/docs/reference/rest/v1/speech/longrunningrecognize (verificado em 2026-07-02)
- API de fala para texto da OpenAI: https://developers.openai.com/api/docs/guides/speech-to-text (verificado em 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.