|
Documentação
Agende uma demoPlataforma
PlataformaMCPCLIAPI
Workflows
GuiasChangelog

Boas-vindas

  • Visão geral
  • Autenticação
  • Erros e códigos de status
  • Assinaturas de webhook

Localização

  • Visão geral
  • Criar jobs
  • Bloquear chaves não traduzíveis
  • Acompanhar um grupo de jobs
  • Buscar um job
  • Listar jobs
  • Entrega de webhook
  • Progresso em tempo real (WebSocket)

Pipeline

  • Visão geral
  • Edição por IA antes da localização
  • Revisão humana
  • avaliação por IA (pós-edição)
  • Reescreva para soar natural
  • Verificação por retradução
  • Configure o pipeline
  • Acompanhe execuções do pipeline

Provisionamento

  • Visão geral
  • Criar um job de provisionamento
  • Tipos de fonte
  • O que a IA extrai
  • Entrega de webhook
  • Progresso em tempo real (WebSocket)

Síncrono

  • Localize
  • Recognize

Gerenciamento do engine

  • Sugestões do engine

Entrega de webhook

Você criou um grupo de jobs e recebeu um 202 de volta em milissegundos. As traduções agora estão rodando em segundo plano, um job por idioma. Você até poderia consultar cada job até ele terminar — mas prefere não manter um loop de polling só para descobrir que o alemão já está pronto. O que você quer é que o seu servidor seja avisado no instante em que cada idioma ficar pronto.

É exatamente para isso que serve o webhook. Quando você passa uma callbackUrl ao criar os jobs, a Lingo.dev envia o resultado por POST para essa URL assim que cada job atinge um estado terminal — um POST por idioma, no exato momento em que ele fica pronto. Um idioma traduzido com sucesso chega como translation.completed com os dados. Um idioma que falha chega como translation.failed com o erro. Você é informado de qualquer jeito, idioma por idioma, sem precisar consultar.

Esta página explica os dois formatos de payload e como lidar com eles. A entrega é assinada e reenviada em caso de falha — essa mecânica é compartilhada com o provisioning e fica na página de verificação de assinatura de webhook, com links nos pontos em que você vai precisar dela.

Nesta página

  • Como a entrega funciona
  • O payload de conclusão
  • O payload de falha
  • Como lidar com um webhook
  • Quando a entrega não é a ferramenta certa

Como a entrega funciona#

Cada idioma em um grupo é um job independente. No instante em que um deles atinge um estado terminal, o resultado é entregue separadamente para sua callbackUrl — a Lingo.dev não espera o idioma mais lento nem agrupa tudo em uma única chamada. Quatorze idiomas de destino significam até quatorze POSTs, chegando conforme cada idioma termina, na ordem em que terminarem.

Defina o destino por requisição com callbackUrl ao criar o grupo de jobs, ou configure um padrão da organização no dashboard, que todos os grupos herdam. Uma callbackUrl definida por requisição substitui o padrão da organização para aquele grupo.

Somente HTTPS

callbackUrl precisa usar HTTPS. Uma URL HTTP é rejeitada com 400 quando você cria o job — o webhook é assinado, e um payload assinado em texto puro perde totalmente o sentido.

Dois formatos de payload trafegam pela rede, diferenciados pelo campo type: translation.completed e translation.failed. Ambos informam o job, o grupo ao qual pertencem e o idioma que carregam, para que um único handler possa fazer o roteamento com base em type e atualizar o registro certo.

Lide bem com tipos de evento desconhecidos

Hoje, a transmissão inclui translation.completed e translation.failed. Trate esse conjunto como aberto — faça branch dos tipos que você conhece e ignore o restante, para que um tipo de evento futuro não quebre um handler já em produção.

O payload de conclusão#

Quando um job termina com sucesso, o payload traz o data traduzido — no mesmo formato que você obteria ao buscar o job, só que enviado para você em vez de consultado por polling. O data espelha a estrutura que você enviou: todas as strings traduzidas, todos os valores que não são string (números, booleanos, null) preservados, com o aninhamento intacto.

json
{
  "type": "translation.completed",
  "jobId": "ljb_A1b2C3d4E5f6G7h8",
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "sourceLocale": "en",
  "targetLocale": "de",
  "data": {
    "id": "course_101",
    "title": "Einführung in maschinelles Lernen",
    "steps": [
      { "heading": "Was ist ML?", "body": "Maschinelles Lernen ist ein Teilbereich der künstlichen Intelligenz." },
      { "heading": "Überwachtes Lernen", "body": "Trainieren eines Modells mit gelabelten Daten." }
    ],
    "metadata": { "author": "Dr. Smith", "difficulty": "beginner" }
  }
}
CampoDescrição
typetranslation.completed
jobIdO job que terminou (prefixo ljb_)
groupIdO grupo ao qual ele pertence (prefixo ljg_)
sourceLocaleO idioma de origem que você enviou
targetLocaleO idioma para o qual este payload foi traduzido
dataConteúdo traduzido, no mesmo formato do data que você enviou

Um job que produz saída não é uma falha — então, se ele termina como completed_with_warnings (saída gerada, mas uma etapa opcional do pipeline falhou), ele é entregue como translation.completed, com data utilizável. O webhook informa que o idioma está pronto; os avisos por etapa que explicam essa falha ficam no job individual, que você busca por jobId quando precisar deles.

O payload de falha#

Um idioma pode falhar — um modelo pode atingir o tempo limite, ou todos os modelos configurados podem ficar indisponíveis. Quando um job chega a failed, você ainda é informado. O tipo do payload é translation.failed, e ele traz uma string error no lugar de data:

json
{
  "type": "translation.failed",
  "jobId": "ljb_C3d4E5f6G7h8I9j0",
  "groupId": "ljg_A1b2C3d4E5f6G7h8",
  "sourceLocale": "en",
  "targetLocale": "ja",
  "error": "Model timeout after 30 seconds"
}
CampoDescrição
typetranslation.failed
jobIdO job que falhou
groupIdO grupo ao qual ele pertence
sourceLocaleO idioma de origem que você enviou
targetLocaleO idioma que falhou
errorDescrição da falha em linguagem clara

A falha fica restrita a um único idioma. Se você enviou de, fr e ja, uma falha em ja é entregue em seu próprio POST translation.failed, enquanto de e fr chegam como translation.completed — as traduções em alemão e francês seguem normalmente. O status de falha parcial do grupo reflete essa combinação. Para recuperar o idioma que falhou, envie um novo job só para ele, com uma nova chave de idempotência.

Como lidar com um webhook#

O primeiro pensamento de quem está lendo com ceticismo é o certo: meu handler faz trabalho de verdade — grava no banco, invalida cache, faz fan-out para clientes conectados — então isso não vai manter a conexão aberta tempo demais e acabar estourando o tempo do webhook?

Vai — então não faça a Lingo.dev esperar. Retorne 200 primeiro; processe depois. Confirme o recebimento imediatamente e deixe o trabalho de verdade para depois que a resposta for enviada. Um handler que responde rápido mantém a entrega saudável; um handler que bloqueia por causa do trabalho downstream provoca um retry desnecessário.

javascript
app.post("/webhooks/translations", verifyWebhook, async (req, res) => {
  // Acknowledge first - one POST per locale, the moment it lands.
  res.status(200).send("ok");

  const { type, jobId, groupId, targetLocale, data } = req.body;

  if (type === "translation.completed") {
    await db.content.update({
      where: { groupId },
      data: { [`content_${targetLocale}`]: data },
    });

    // Advance your own progress model - your UI can poll this or receive it over SSE.
    await db.translationProgress.increment({
      where: { groupId },
      data: { completedLanguages: { increment: 1 } },
    });
  }

  if (type === "translation.failed") {
    console.error(`Translation failed: ${jobId} (${targetLocale})`, req.body.error);
  }
});

O middleware verifyWebhook é a única peça que esta página não define. Toda entrega é assinada seguindo a especificação Standard Webhooks, então não é um esquema que você precise decifrar por conta própria. Como fazer essa verificação — e qual é a agenda de retry por trás de uma resposta não 2xx — está documentado em detalhes em verificação de assinatura de webhook, compartilhada com o provisioning. Conecte esse middleware antes de confiar em qualquer payload: um corpo não verificado é um corpo não autenticado.

Verifique antes de confiar no corpo

Seu endpoint é uma URL pública; qualquer pessoa pode enviar um POST para ela. Verifique a assinatura com base no corpo bruto da requisição antes de agir sobre qualquer payload. O passo a passo — headers, HMAC e o segredo whsec_ — está na página de verificação de assinatura.

Quando a entrega não é a ferramenta certa#

O webhook é uma conveniência de envio, não a fonte da verdade. Há dois casos em que faz mais sentido usar outra coisa — e ambos estão a um clique de distância.

Se o seu endpoint estiver fora do ar quando um resultado for entregue, a plataforma tenta novamente — e, se todas as tentativas se esgotarem, o resultado não se perde. Ele continua recuperável por jobId; o callbackStatus do job registra se o envio acabou ou não tendo sucesso. A própria agenda de retry está na página de assinatura e entrega. O webhook poupa você de um loop de polling no caso comum; no incomum, o registro do job continua lá por trás de tudo.

E, se o que você quer é progresso em tempo real em uma UI — um contador passando de 3 de 14 para 4 de 14 conforme os idiomas ficam prontos, em vez de um callback por idioma para o seu servidor — aí o recurso certo é o WebSocket do grupo de jobs, não o webhook.

Progresso em tempo real (WebSocket)
Transmita o progresso do grupo para uma UI com snapshots de estado completo, em vez de callbacks por idioma para o seu servidor.
Verificação de assinatura de webhook
Verifique a assinatura, leia os headers e lide com a agenda de retry — compartilhada por todas as entregas de webhook.
Buscar um job individual
Busque qualquer resultado por jobId, incluindo avisos — a fonte da verdade por trás de cada entrega.

Esta página foi útil?

Max PrilutskiyMax Prilutskiy·Atualizado há 12 dias·7 min de leitura