Webhook de transferência
Receba transferências do assistente em outro sistema e valide com segurança a assinatura HMAC enviada pela TAU.
Webhook de transferência
O webhook de transferência permite que a TAU envie os dados de uma conversa para o seu sistema quando o assistente transfere o atendimento. Você pode conectar esse evento a um CRM, help desk, n8n ou outra automação que aceite requisições HTTP.
Configurar na TAU
- Acesse Configurações → Transferência.
- Em Redirecionar para, selecione Webhook (URL).
- Informe uma URL HTTPS pública que aceite requisições
POSTcom JSON. - Em Autenticação do Webhook, selecione Gerar Nova API Key para Webhook.
- Copie a chave quando ela for exibida e guarde-a em um gerenciador de segredos. Você usará essa mesma chave para validar as requisições recebidas.
A chave deve permanecer somente no servidor ou na credencial protegida da sua ferramenta de automação. Nunca coloque a chave em código executado no navegador, páginas públicas ou repositórios.
Como a assinatura funciona
Quando existe uma API key configurada, cada requisição inclui:
| Item | Valor |
|---|---|
| Método | POST |
| Conteúdo | JSON em UTF-8 |
| Cabeçalho | X-TAU-Signature |
| Algoritmo | HMAC-SHA256 |
| Formato | 64 caracteres hexadecimais, sem o prefixo sha256= |
| Mensagem assinada | Corpo bruto da requisição, exatamente como foi recebido |
| Segredo | API key do webhook gerada na TAU |
A validação segue esta regra:
assinatura_esperada = HEX(HMAC_SHA256(api_key, corpo_bruto))Depois, compare assinatura_esperada com o valor de X-TAU-Signature usando uma função de comparação segura.
Calcule o HMAC sobre o corpo bruto. Não use JSON.stringify, não reordene campos e não formate o JSON novamente. Espaços, quebras de linha e a ordem dos campos alteram a assinatura.
Se nenhuma API key estiver configurada, o cabeçalho X-TAU-Signature não será enviado. Para integrações em produção, mantenha a autenticação habilitada e rejeite requisições sem assinatura.
A assinatura confirma que o corpo foi gerado com a chave compartilhada e não foi alterado. Ela não contém timestamp. Se uma ação não puder ser repetida, implemente também uma proteção contra processamento duplicado no sistema de destino.
Exemplo em Node.js com Express
O exemplo abaixo preserva os bytes recebidos antes de o Express interpretar o JSON:
const express = require('express');
const {
createHmac,
timingSafeEqual,
} = require('crypto');
const app = express();
const secret = process.env.TAU_WEBHOOK_SECRET;
if (!secret) {
throw new Error('TAU_WEBHOOK_SECRET não configurado');
}
app.use(express.json({
verify: (req, _res, buffer) => {
req.rawBody = Buffer.from(buffer);
},
}));
function isValidSignature(rawBody, receivedSignature) {
if (!/^[a-f0-9]{64}$/i.test(receivedSignature)) {
return false;
}
const expectedSignature = createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return timingSafeEqual(
Buffer.from(expectedSignature, 'hex'),
Buffer.from(receivedSignature, 'hex'),
);
}
app.post('/webhooks/tau', (req, res) => {
const receivedSignature = req.get('X-TAU-Signature') || '';
if (!isValidSignature(req.rawBody, receivedSignature)) {
return res.status(401).json({ error: 'Assinatura inválida' });
}
// A assinatura é válida. Processe req.body aqui.
return res.sendStatus(204);
});
app.listen(3000);Exemplo em Python com FastAPI
import hashlib
import hmac
import json
import os
from fastapi import FastAPI, HTTPException, Request, Response
app = FastAPI()
secret = os.environ["TAU_WEBHOOK_SECRET"].encode("utf-8")
@app.post("/webhooks/tau")
async def receive_tau_webhook(request: Request) -> Response:
raw_body = await request.body()
received_signature = request.headers.get("X-TAU-Signature", "")
expected_signature = hmac.new(
secret,
raw_body,
hashlib.sha256,
).hexdigest()
if not hmac.compare_digest(expected_signature, received_signature):
raise HTTPException(status_code=401, detail="Assinatura inválida")
payload = json.loads(raw_body)
# A assinatura é válida. Processe payload aqui.
return Response(status_code=204)Exemplo em PHP
<?php
$secret = getenv('TAU_WEBHOOK_SECRET');
$rawBody = file_get_contents('php://input');
$receivedSignature = $_SERVER['HTTP_X_TAU_SIGNATURE'] ?? '';
if (!$secret) {
http_response_code(500);
exit('Webhook não configurado');
}
$expectedSignature = hash_hmac('sha256', $rawBody, $secret);
if (!hash_equals($expectedSignature, $receivedSignature)) {
http_response_code(401);
exit('Assinatura inválida');
}
$payload = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
// A assinatura é válida. Processe $payload aqui.
http_response_code(204);Configurar no n8n
No n8n, use o fluxo abaixo para preservar o corpo original, calcular o HMAC com uma credencial protegida e interromper requisições inválidas:
Webhook → Crypto (Hmac) → Code (comparação segura) → If
├─ true → Respond to Webhook (204) → sua automação
└─ false → Respond to Webhook (401)1. Nó Webhook
Configure:
| Campo | Valor |
|---|---|
| HTTP Method | POST |
| Authentication | None |
| Respond | Using 'Respond to Webhook' Node |
| Options → Raw Body | ativado |
Copie a URL de teste para validar o fluxo. Quando terminar, publique o workflow e use a URL de produção na configuração da TAU.
A opção Raw Body é obrigatória. Ela preserva o corpo recebido no campo binário data. Usar somente $json.body pode produzir uma assinatura diferente.
2. Credencial e nó Crypto
Crie uma credencial do tipo Hmac Secret e cole nela a API key gerada na TAU. Depois, adicione um nó Crypto com:
| Campo | Valor |
|---|---|
| Action | Hmac |
| Credential | a credencial Hmac Secret criada acima |
| Binary File | ativado |
| Binary Property Name | data |
| Type | SHA256 |
| Encoding | HEX |
| Property Name | calculatedSignature |
O segredo fica na credencial do n8n e não precisa aparecer no código do workflow.
3. Nó Code para comparação segura
Adicione um nó Code, escolha JavaScript e Run Once for All Items, e cole:
const crypto = require('crypto');
const item = $input.first();
const expected = String(item.json.calculatedSignature || '').trim();
const received = String(
item.json.headers?.['x-tau-signature'] || '',
).trim();
let signatureValid = false;
if (
/^[a-f0-9]{64}$/i.test(expected) &&
/^[a-f0-9]{64}$/i.test(received)
) {
signatureValid = crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(received, 'hex'),
);
}
return [{
json: {
...item.json,
signatureValid,
},
binary: item.binary,
}];No n8n Cloud, o módulo crypto está disponível no nó Code. Em instalações self-hosted, o administrador precisa permitir esse módulo com NODE_FUNCTION_ALLOW_BUILTIN=crypto antes de usar o exemplo.
O n8n normalmente disponibiliza nomes de cabeçalhos HTTP em letras minúsculas. Por isso, o exemplo lê x-tau-signature.
4. Nós If e Respond to Webhook
- No nó If, verifique se
{{ $json.signatureValid }}étrue. - Conecte a saída true a um Respond to Webhook, código
204ou outro código2xx. - Conecte a saída desse Respond to Webhook à sua automação. O n8n envia a resposta e continua o workflow com os dados de entrada.
- Conecte a saída false a outro Respond to Webhook, código
401. - Não conecte a saída inválida aos nós que criam contatos, notificam a equipe ou executam outras ações.
A TAU aguarda a resposta do endpoint por até aproximadamente 10 segundos. Responda com 2xx assim que a requisição válida for aceita, antes de iniciar processamentos mais demorados.
Vetor de teste
Use este exemplo apenas para conferir se sua implementação de HMAC está correta:
Segredo: teste_tau_webhook
Corpo UTF-8: {"summary":"Atendimento humano solicitado."}
Assinatura esperada: f3c8c119d538dba9ff20c7b7d746f5665a14ab5a0870229906d2a637aedcd499Qualquer espaço ou quebra de linha adicional no corpo produzirá outra assinatura.
Checklist de produção
- Use somente URLs HTTPS.
- Guarde a API key em variável de ambiente ou credencial protegida.
- Valide a assinatura antes de processar os dados ou executar qualquer efeito.
- Rejeite assinatura ausente ou inválida com
401ou403. - Compare assinaturas com função segura, como
timingSafeEqual,compare_digestouhash_equals. - Retorne um código
2xxpara requisições válidas aceitas. - Não registre a API key nem o corpo completo da conversa em logs.