Conferir a assinatura
Todo envio de um webhook — e de uma ação Enviar para outro sistema com Assinar o envio — leva o cabeçalho:
X-Tai-Assinatura: t=1791374691,v1=5f0c9a…e41bté o instante da assinatura, em segundos desde 1970 (UTC).v1é o HMAC-SHA256, em hexadecimal minúsculo, do texto<t>.<corpo>, com o segredo do webhook como chave. O corpo é o texto exato recebido, byte a byte.
Como conferir
Seção intitulada “Como conferir”- Leia o corpo cru, antes de qualquer parse de JSON.
- Separe
tev1do cabeçalho. - Calcule
HMAC-SHA256(segredo, t + "." + corpo)em hexadecimal. - Compare com
v1em tempo constante. - Recuse se
testiver longe do seu relógio — 5 minutos é uma boa tolerância.
import crypto from 'node:crypto'import express from 'express'
const SEGREDO = process.env.TAI_WEBHOOK_SECRETconst app = express()
app.post('/tai/webhook', express.raw({ type: 'application/json' }), (req, res) => { const cabecalho = req.get('X-Tai-Assinatura') ?? '' const partes = Object.fromEntries(cabecalho.split(',').map((p) => p.trim().split('='))) const t = Number(partes.t) const corpo = req.body.toString('utf8')
const esperado = crypto.createHmac('sha256', SEGREDO).update(`${t}.${corpo}`).digest('hex') const valida = partes.v1?.length === esperado.length && crypto.timingSafeEqual(Buffer.from(partes.v1), Buffer.from(esperado)) if (!valida || Math.abs(Date.now() / 1000 - t) > 300) return res.sendStatus(401)
const evento = JSON.parse(corpo) fila.publicar(req.get('X-Tai-Entrega'), evento) // processe depois res.sendStatus(204)})import hashlib, hmac, os, timefrom flask import Flask, request, abort
SEGREDO = os.environ["TAI_WEBHOOK_SECRET"].encode()app = Flask(__name__)
@app.post("/tai/webhook")def receber(): partes = dict(p.strip().split("=", 1) for p in request.headers.get("X-Tai-Assinatura", "").split(",") if "=" in p) t = partes.get("t", "0") corpo = request.get_data() # bytes crus
esperado = hmac.new(SEGREDO, t.encode() + b"." + corpo, hashlib.sha256).hexdigest() if not hmac.compare_digest(esperado, partes.get("v1", "")) or abs(time.time() - int(t)) > 300: abort(401)
fila.publicar(request.headers["X-Tai-Entrega"], request.get_json()) # processe depois return "", 204Trocar o segredo
Seção intitulada “Trocar o segredo”Na aba Webhooks, Gerar outro segredo gera um segredo novo, mostrado uma única vez; a partir dali os envios saem com ele. Atualize o seu sistema logo em seguida — ou aceite os dois segredos por alguns minutos durante a troca.
Sem assinatura
Seção intitulada “Sem assinatura”As ações dos gatilhos do Atendimento e as ações Enviar para outro sistema sem Assinar o envio
não levam X-Tai-Assinatura. Nesses casos, autentique por um cabeçalho com token (nas ações que
aceitam cabeçalhos) ou por um segredo no caminho da URL.
Referência gerada do contrato da API em 30 de outubro de 2026. taitecnologia.com · Termos de uso · Privacidade
© 2026 T AI TECNOLOGIA LTDA