OneSendzDevelopers
Usar a API

Receber: webhooks

Em vez de perguntar o tempo todo, deixe a OneSendz avisar o seu sistema quando algo acontece.

Cadastrar

bash
curl -X POST https://dev.onesendz.com/api/v1/criar_webhook \
  -H "Authorization: Bearer $ONESENDZ_API_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://seu-app.com/webhooks/onesendz", "eventos": ["mensagem.recebida", "mensagem.falhou"], "descricao": "meu-app produção"}'

O endereço precisa ser https e público. A resposta traz o segredo, que aparece uma vez só. Teste na hora com testar_webhook. Até 10 endereços por conta.

Eventos

EventoQuando chega
mensagem.recebidaO cliente escreveu
mensagem.entregueUma mensagem enviada chegou no celular do cliente
mensagem.lidaO cliente leu
mensagem.falhouNão foi entregue. Vem com erro: código da Meta, motivo e como resolver
contato.criadoEntrou um contato novo
contato.etiqueta_adicionadaUm contato ganhou uma etiqueta
conversa.atribuidaA conversa ganhou um atendente
conversa.pediu_atendenteA IA ou o robô passou a conversa para uma pessoa
conversa.encerradaA conversa foi marcada como resolvida
lead.qualificadoA IA de atendimento levantou os dados do lead

O que chega

Um POST com JSON. Nos eventos de status, dados.mensagem.id é o mensagem_id que o envio devolveu.

json
{
  "id": "0b1c8f5e-...",
  "tipo": "mensagem.falhou",
  "criado_em": "2026-10-26T17:45:10Z",
  "organizacao_id": "...",
  "dados": {
    "mensagem": { "id": "6906fb96-...", "status": "failed", "template": "pedido_enviado" },
    "conversa": { "id": "...", "link": "..." },
    "contato": { "id": "...", "nome": "Marina", "telefone": "+5511999990000" },
    "erro": { "codigo": "131047", "motivo": "Janela de 24h fechada", "como_resolver": "O cliente não escreveu nas últimas 24h. Para falar com ele, use um template aprovado." }
  }
}

Conferir a assinatura

Cada aviso traz:

Recuse assinatura errada ou com mais de 5 minutos. Use o corpo cru, antes de converter para JSON.

javascript
// Node.js (Express)
import crypto from "node:crypto";

app.post("/webhooks/onesendz", express.raw({ type: "application/json" }), (req, res) => {
  const ts = req.header("X-OneSendz-Timestamp");
  const assinatura = req.header("X-OneSendz-Signature") ?? "";
  const esperado = "sha256=" + crypto.createHmac("sha256", process.env.ONESENDZ_WEBHOOK_SECRET)
    .update(`${ts}.${req.body}`).digest("hex");
  const recente = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  if (!recente || assinatura.length !== esperado.length ||
      !crypto.timingSafeEqual(Buffer.from(assinatura), Buffer.from(esperado))) {
    return res.sendStatus(401);
  }
  const evento = JSON.parse(req.body);
  // ignore se evento.id já foi processado; depois trate evento.tipo
  res.sendStatus(200);
});
python
# Python (Flask)
import hmac, hashlib, time, os
from flask import request, abort

@app.post("/webhooks/onesendz")
def onesendz():
    ts = request.headers.get("X-OneSendz-Timestamp", "")
    assinatura = request.headers.get("X-OneSendz-Signature", "")
    corpo = request.get_data(as_text=True)
    esperado = "sha256=" + hmac.new(os.environ["ONESENDZ_WEBHOOK_SECRET"].encode(), f"{ts}.{corpo}".encode(), hashlib.sha256).hexdigest()
    if abs(time.time() - int(ts or 0)) > 300 or not hmac.compare_digest(assinatura, esperado):
        abort(401)
    evento = request.get_json()
    return "", 200

Reenvios