Webhook de detrator e eventos assinados
O ProFeedback avisa o seu sistema por POST HTTPS a cada evento escolhido. Cadastre os endpoints no painel, em Integrações, ou por POST /v1/webhooks.
Eventos
| Evento | Quando |
|---|---|
response.created | Toda nota registrada (API, link de pesquisa ou painel). |
response.detractor | Nota de 0 a 6, junto com o response.created. Use para tratar o cliente insatisfeito. |
customer.created | Cliente novo (API, importação CSV, painel ou nota com external_id novo). |
Corpo
JSON com id do evento, event, created_at, sandbox (true quando veio de chave pf_test_) e data:
{"created_at": "2026-10-23T10:00:00-03:00", "data": {"attributes": {"atendente": "Ana"}, "category": "detractor", "comment": "Demorou para responder.", "created_at": "2026-10-23T10:00:00-03:00", "customer": {"external_id": "crm-001", "id": "8b6f5c1e-2f0a-4d43-9a57-3f1c9a0b7e21", "name": "Maria Souza"}, "id": "0e7d3a52-6c1b-4f7e-8d2a-91b5c4e6f3a0", "score": 4, "source": "link"}, "event": "response.detractor", "id": "5a1c9e47-3b2d-4f60-a8e1-7c2f4d9b6e15", "sandbox": false}
Cabeçalhos
X-ProFeedback-Signature | sha256=<hex>: HMAC-SHA256 do carimbo de tempo mais o corpo. |
X-ProFeedback-Timestamp | Instante do envio em segundos Unix. |
X-ProFeedback-Event | Nome do evento. |
X-ProFeedback-Delivery | Id da entrega (use para descartar repetição). |
Validar a assinatura
O segredo do endpoint aparece uma vez, ao criar ou rotacionar. A assinatura cobre "<timestamp>." + corpo_bruto: calcule sobre o corpo exatamente como chegou (sem reserializar o JSON), compare em tempo constante e recuse carimbos com mais de 5 minutos.
Python
import hashlib
import hmac
import time
def assinatura_confere(secret: str, corpo_bruto: bytes, timestamp: str, assinatura: str) -> bool:
if abs(time.time() - int(timestamp)) > 300:
return False
esperado = "sha256=" + hmac.new(
secret.encode(), f"{timestamp}.".encode() + corpo_bruto, hashlib.sha256
).hexdigest()
return hmac.compare_digest(esperado, assinatura)
Node.js
const crypto = require("crypto");
function assinaturaConfere(secret, corpoBruto, timestamp, assinatura) {
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const esperado = "sha256=" + crypto
.createHmac("sha256", secret)
.update(`${timestamp}.`)
.update(corpoBruto) // Buffer do corpo cru, ex.: express.raw({ type: "application/json" })
.digest("hex");
const a = Buffer.from(esperado);
const b = Buffer.from(assinatura || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
Exemplo conferível
Com o segredo whsec_exemplo_nao_use_em_producao, X-ProFeedback-Timestamp: 1792764000 e o corpo acima (exatamente esses bytes), a assinatura é:
X-ProFeedback-Signature: sha256=33f33fd0e544da4546a177aa1d767bedfa8b5ff05ca03c6bc299068ebf8697c2
Entrega e retentativas
- Responda 2xx em até 10 segundos; processe o evento depois, em fila.
- Sem 2xx, até 5 tentativas com espera crescente (a partir de 60 segundos, teto de 1 hora).
- A mesma entrega pode chegar mais de uma vez: use o
X-ProFeedback-Deliveryou oiddo evento para não processar duas vezes. - Destinos internos (IP privado, localhost) são recusados.
- Entregas e reenvio: painel, em Integrações, ou
GET /v1/webhooks/deliveriesePOST /v1/webhooks/deliveries/{id}/resend. Teste comPOST /v1/webhooks/{id}/teste troque o segredo comPOST /v1/webhooks/{id}/rotate-secret.