API & MCP
Webhooks de saída
Em vez de o seu sistema perguntar de tempos em tempos se apareceu algo novo, o ionluz avisa. Cadastre uma URL em API e cobertura, em qualquer plano, guarde o segredo que aparece na hora e passe a receber os eventos da sua conta.
| Evento | Quando dispara |
|---|---|
lead.criado | Uma proposta foi gravada na sua conta: pela página pública de captação, por POST /v1/quote com gravação ou pelo MCP com persist. |
proposta.aberta | O cliente final abriu a proposta pela primeira vez. Sai uma vez por proposta, mesmo gatilho do e-mail de aviso. |
proposta.aceita | O cliente final aceitou a proposta na página dele, dentro da validade. Sai uma vez por proposta, mesmo gatilho do e-mail de aceite. |
ping | Você clicou em Testar no painel. Use para validar a sua verificação de assinatura antes de contar com os eventos reais. |
O que chega
O lead.criado da gravação do exemplo de Cotação:
POST https://seucrm.com.br/hooks/ionluz
X-Ionluz-Event: lead.criado
X-Ionluz-Delivery: evt_3f1a9c72b0d84e5f16
X-Ionluz-Signature: t=1789012345,v1=6b1f...c904
Content-Type: application/json
{
"id": "evt_3f1a9c72b0d84e5f16",
"evento": "lead.criado",
"criadoEm": "2026-09-25T14:05:00.000Z",
"data": {
"proposalId": "clx8h2k9a0001abcd",
"origem": "api",
"criadaEm": "2026-09-25T14:05:00.000Z",
"potenciaKwp": 5.72,
"valorFinal": 14296.8,
"paybackAnos": 2.1406530441031313,
"consumoKwhMes": 620,
"cliente": {
"nome": "Cliente Exemplo",
"email": "cliente@exemplo.com.br",
"telefone": "(15) 99999-0000",
"cidade": "Sorocaba",
"uf": "SP"
},
"links": {
"proposta": "https://app.ionluz.com.br/p/clx8h2k9a0001abcd?t=...",
"pdf": "https://app.ionluz.com.br/api/pub/clx8h2k9a0001abcd/pdf?t=..."
}
}
}Conferindo a assinatura
O cabeçalho X-Ionluz-Signature vem no formato t=<unix>,v1=<hmac-sha256-hex>. O HMAC é calculado com o seu segredo sobre a string <t>.<corpo bruto>. Compare em tempo constante, confira o tamanho antes da comparação (com tamanhos diferentes, timingSafeEqual lança erro) e recuse timestamp com mais de 5 minutos, o que fecha a porta para o reenvio de uma entrega capturada.
// Express: guarde o corpo BRUTO, a assinatura é sobre os bytes recebidos
app.post("/hooks/ionluz", express.raw({ type: "application/json" }), (req, res) => {
const bruto = req.body.toString("utf8");
const partes = Object.fromEntries(
String(req.get("X-Ionluz-Signature") || "").split(",").map(p => p.split("="))
);
const esperado = crypto.createHmac("sha256", process.env.IONLUZ_WEBHOOK_SECRET)
.update(partes.t + "." + bruto).digest("hex");
const assinaturaOk =
typeof partes.v1 === "string" && esperado.length === partes.v1.length &&
crypto.timingSafeEqual(Buffer.from(esperado), Buffer.from(partes.v1));
const recente = Math.abs(Date.now() / 1000 - Number(partes.t)) < 300;
if (!assinaturaOk || !recente) return res.sendStatus(401);
res.sendStatus(200); // responda primeiro
processar(JSON.parse(bruto)); // trabalhe depois, fora do ciclo da entrega
});Entrega
- Timeout de 8 segundos e uma retentativa, em falha de rede,
5xxou429. Qualquer outro4xxencerra a entrega, porque repetir não mudaria o resultado. - A retentativa reenvia o mesmo corpo e a mesma assinatura. Deduplique pelo
X-Ionluz-Delivery, que é oiddo envelope. - Responda
2xxprimeiro e processe depois. Enquanto o seu servidor pensa, o relógio dos 8 segundos corre. - Sem fila de reprocessamento: o que acontecer com o webhook removido ou fora do ar por muito tempo não é reenviado depois. Para reconciliar, use
GET /v1/proposals. - Só
httpse host público. Redirect não é seguido. - O painel mostra o status da última entrega. Rotacionar o segredo vale na entrega seguinte.
- Emitir um evento nunca atrasa nem derruba a resposta ao seu cliente: a cotação volta antes, o aviso sai depois.
- Nas contas com o motor novo,
lead.criadosai quando o pedido é gravado, com ovalorFinalda sua tabela, mesmo que o cliente ainda não veja preço ("eu aprovo antes" pendente ou publicação só com o pedido). Esse número é para o seu sistema: antes de mandá-lo ao cliente, confiraaprovacaoepublicacaoemGET /v1/proposals/{id}. A aprovação não dispara evento.
API v1 · ionluz, propostas solares honestas. Dúvidas? Cite o
requestId ao escrever para suporte@ionluz.com.br.