Plataforma TAU

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

  1. Acesse Configurações → Transferência.
  2. Em Redirecionar para, selecione Webhook (URL).
  3. Informe uma URL HTTPS pública que aceite requisições POST com JSON.
  4. Em Autenticação do Webhook, selecione Gerar Nova API Key para Webhook.
  5. 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:

ItemValor
MétodoPOST
ConteúdoJSON em UTF-8
CabeçalhoX-TAU-Signature
AlgoritmoHMAC-SHA256
Formato64 caracteres hexadecimais, sem o prefixo sha256=
Mensagem assinadaCorpo bruto da requisição, exatamente como foi recebido
SegredoAPI 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:

CampoValor
HTTP MethodPOST
AuthenticationNone
RespondUsing 'Respond to Webhook' Node
Options → Raw Bodyativado

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:

CampoValor
ActionHmac
Credentiala credencial Hmac Secret criada acima
Binary Fileativado
Binary Property Namedata
TypeSHA256
EncodingHEX
Property NamecalculatedSignature

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

  1. No nó If, verifique se {{ $json.signatureValid }} é true.
  2. Conecte a saída true a um Respond to Webhook, código 204 ou outro código 2xx.
  3. 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.
  4. Conecte a saída false a outro Respond to Webhook, código 401.
  5. 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: f3c8c119d538dba9ff20c7b7d746f5665a14ab5a0870229906d2a637aedcd499

Qualquer 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 401 ou 403.
  • Compare assinaturas com função segura, como timingSafeEqual, compare_digest ou hash_equals.
  • Retorne um código 2xx para requisições válidas aceitas.
  • Não registre a API key nem o corpo completo da conversa em logs.

On this page