O Triglit envia webhooks para seus endpoints quando eventos importantes ocorrem durante a execução de workflows, como conclusão, falhas ou pausas. Os webhooks são entregues através do Svix , uma plataforma confiável de entrega de webhooks.
O que são Webhooks?
Webhooks são notificações HTTP enviadas pelo Triglit para seus endpoints quando eventos ocorrem. Isso permite que você reaja a eventos em tempo real sem precisar fazer polling constante.
Eventos Disponíveis
O Triglit envia os seguintes eventos de execução de workflows:
run.started : Execução (run) iniciada
run.completed : Execução concluída com sucesso
run.failed : Execução falhou
run.cancelled : Execução cancelada
run.paused : Execução pausada (aguardando retomada)
run.resumed : Execução retomada após pausa
Configuração
1. Configurar Webhook no Frontend
A configuração de webhooks é feita através do painel do Triglit (frontend), não via API. No painel, você pode:
Acessar as configurações de webhooks
Adicionar um endpoint para receber notificações
Selecionar quais eventos deseja receber
Ver o secret para validação
A configuração de webhooks é feita apenas pelo frontend do Triglit. Não há endpoints de API para cadastro de webhooks.
2. Implementar Endpoint
Como os webhooks são entregues via Svix , você precisa validar a assinatura usando o SDK do Svix ou validar manualmente:
JavaScript - Usando SDK do Svix
Python - Usando SDK do Svix
const svix = require ( 'svix' );
const webhook = new svix . Webhook ( process . env . SVIX_SECRET );
app . post ( '/webhooks/triglit' , express . raw ({ type: 'application/json' }), ( req , res ) => {
try {
// Validar assinatura usando Svix
const payload = webhook . verify ( req . body , {
'svix-id' : req . headers [ 'svix-id' ],
'svix-timestamp' : req . headers [ 'svix-timestamp' ],
'svix-signature' : req . headers [ 'svix-signature' ]
});
const event = JSON . parse ( payload );
switch ( event . type ) {
case 'run.completed' :
handleRunCompleted ( event . data );
break ;
case 'run.failed' :
handleRunFailed ( event . data );
break ;
case 'run.paused' :
handleRunPaused ( event . data );
break ;
}
res . json ({ received: true });
} catch ( error ) {
console . error ( 'Webhook validation failed:' , error );
res . status ( 401 ). json ({ error: 'Invalid signature' });
}
});
Estrutura do Evento
Os eventos enviados pelo Triglit seguem esta estrutura:
{
"type" : "run.completed" ,
"data" : {
"runId" : "run_456" ,
"tenantId" : "tenant_abc" ,
"subTenantId" : "sub_tenant_xyz" ,
"workflowVersionId" : "version_789" ,
"timestamp" : "2024-01-15T10:00:00Z" ,
"status" : "succeeded"
}
}
O campo subTenantId é opcional e estará presente apenas quando a execução ocorrer em um ambiente de sub-tenant. Se não houver sub-tenant associado, este campo não será incluído no payload.
Estrutura por Tipo de Evento
run.started :
{
"type" : "run.started" ,
"data" : {
"runId" : "run_456" ,
"tenantId" : "tenant_abc" ,
"subTenantId" : "sub_tenant_xyz" ,
"workflowVersionId" : "version_789" ,
"timestamp" : "2024-01-15T10:00:00Z"
}
}
run.completed :
{
"type" : "run.completed" ,
"data" : {
"runId" : "run_456" ,
"tenantId" : "tenant_abc" ,
"subTenantId" : "sub_tenant_xyz" ,
"workflowVersionId" : "version_789" ,
"timestamp" : "2024-01-15T10:00:00Z" ,
"status" : "succeeded"
}
}
run.failed :
{
"type" : "run.failed" ,
"data" : {
"runId" : "run_456" ,
"tenantId" : "tenant_abc" ,
"subTenantId" : "sub_tenant_xyz" ,
"workflowVersionId" : "version_789" ,
"timestamp" : "2024-01-15T10:00:00Z" ,
"status" : "failed" ,
"error" : "Error message (opcional)"
}
}
run.cancelled :
{
"type" : "run.cancelled" ,
"data" : {
"runId" : "run_456" ,
"tenantId" : "tenant_abc" ,
"subTenantId" : "sub_tenant_xyz" ,
"workflowVersionId" : "version_789" ,
"timestamp" : "2024-01-15T10:00:00Z" ,
"status" : "cancelled"
}
}
run.paused :
{
"type" : "run.paused" ,
"data" : {
"runId" : "run_456" ,
"tenantId" : "tenant_abc" ,
"subTenantId" : "sub_tenant_xyz" ,
"workflowVersionId" : "version_789" ,
"timestamp" : "2024-01-15T10:00:00Z" ,
"status" : "paused" ,
"pauseReason" : "Waiting for user input" ,
"resumeToken" : "resume_token_123" ,
"timeoutAt" : "2024-01-15T10:05:00Z"
}
}
run.resumed :
{
"type" : "run.resumed" ,
"data" : {
"runId" : "run_456" ,
"tenantId" : "tenant_abc" ,
"subTenantId" : "sub_tenant_xyz" ,
"workflowVersionId" : "version_789" ,
"timestamp" : "2024-01-15T10:00:00Z" ,
"status" : "resumed" ,
"resumeToken" : "resume_token_123"
}
}
Validação de Assinatura
O Svix envia webhooks com assinaturas nos headers:
svix-id : ID único do evento
svix-timestamp : Timestamp do evento
svix-signature : Assinatura HMAC SHA256
Sempre valide a assinatura do webhook usando o SDK do Svix ou validação manual. Nunca processe webhooks sem validar a assinatura.
Exemplo Completo
const express = require ( 'express' );
const { Webhook } = require ( 'svix' );
const app = express ();
const webhook = new Webhook ( process . env . SVIX_SECRET );
app . post ( '/webhooks/triglit' , express . raw ({ type: 'application/json' }), async ( req , res ) => {
try {
// Validar assinatura usando Svix
const payload = webhook . verify ( req . body , {
'svix-id' : req . headers [ 'svix-id' ],
'svix-timestamp' : req . headers [ 'svix-timestamp' ],
'svix-signature' : req . headers [ 'svix-signature' ]
});
const event = JSON . parse ( payload );
console . log ( `Received event: ${ event . type } ` );
switch ( event . type ) {
case 'run.started' :
await handleRunStarted ( event . data );
break ;
case 'run.completed' :
await handleRunCompleted ( event . data );
break ;
case 'run.failed' :
await handleRunFailed ( event . data );
break ;
case 'run.cancelled' :
await handleRunCancelled ( event . data );
break ;
case 'run.paused' :
await handleRunPaused ( event . data );
break ;
case 'run.resumed' :
await handleRunResumed ( event . data );
break ;
}
res . json ({ received: true });
} catch ( error ) {
console . error ( 'Webhook error:' , error );
res . status ( 401 ). json ({ error: 'Invalid signature' });
}
});
async function handleRunStarted ( data ) {
console . log ( `Run ${ data . runId } started` );
// Lógica para quando uma execução inicia
}
async function handleRunCompleted ( data ) {
console . log ( `Run ${ data . runId } completed successfully` );
// Atualizar status no seu sistema
// await updateOrderStatus(data.runId, 'processed');
}
async function handleRunFailed ( data ) {
console . error ( `Run ${ data . runId } failed:` , data . error );
// Atualizar status e notificar equipe
// await updateOrderStatus(data.runId, 'failed');
// await notifyTeam(data.runId, data.error);
}
async function handleRunCancelled ( data ) {
console . log ( `Run ${ data . runId } was cancelled` );
// Lógica para execução cancelada
}
async function handleRunPaused ( data ) {
console . log ( `Run ${ data . runId } paused: ${ data . pauseReason } ` );
// Salvar resumeToken para retomar depois
// await saveResumeToken(data.runId, data.resumeToken);
}
async function handleRunResumed ( data ) {
console . log ( `Run ${ data . runId } resumed` );
// Lógica para quando execução é retomada
}
app . listen ( 3000 );
Retries e Confiabilidade
O Svix gerencia automaticamente retries e entrega confiável de webhooks:
Retries automáticos : O Svix retenta automaticamente em caso de falha
Entrega garantida : Webhooks são entregues de forma confiável
Timeout : Configurável no Svix
Dead Letter Queue : Webhooks que falham persistentemente são armazenados
Sempre retorne 200 OK rapidamente após validar a assinatura:
app . post ( '/webhooks/triglit' , async ( req , res ) => {
try {
// Validar assinatura
const payload = webhook . verify ( req . body , {
'svix-id' : req . headers [ 'svix-id' ],
'svix-timestamp' : req . headers [ 'svix-timestamp' ],
'svix-signature' : req . headers [ 'svix-signature' ]
});
// Retornar imediatamente
res . json ({ received: true });
// Processar de forma assíncrona
processEventAsync ( JSON . parse ( payload ));
} catch ( error ) {
res . status ( 401 ). json ({ error: 'Invalid signature' });
}
});
Boas Práticas
Sempre valide assinaturas usando o SDK do Svix. Nunca processe webhooks sem validação.
Torne handlers idempotentes para lidar com retries do Svix. Use o svix-id para detectar duplicatas.
Retorne 200 OK rapidamente após validar a assinatura e processe eventos de forma assíncrona.
Logue todos os eventos recebidos usando o svix-id para rastreabilidade.
Use sempre HTTPS para webhooks em produção. O Svix requer HTTPS para endpoints de produção.
Configure webhooks através do painel do Triglit. Não é necessário usar a API para isso.
SDKs do Svix
O Svix oferece SDKs oficiais para várias linguagens:
JavaScript/TypeScript : npm install svix
Python : pip install svix
Go : go get github.com/svix/svix-libs/go
Ruby : gem install svix
Java : mvn install svix
C# : dotnet add package Svix
Documentação do Svix Veja a documentação completa do Svix para mais detalhes sobre validação e configuração
Use o Svix CLI ou dashboard para testar webhooks localmente durante desenvolvimento. O Svix também oferece ferramentas para debugging.