Este guia conecta um webhook do rollfuse a uma rota da sua própria aplicação: registrar um endpoint, tratar o payload recebido com um servidor Express mínimo, e usar o histórico de entregas para descobrir por que uma entrega específica falhou.
Registrando um endpoint de webhook
Um endpoint de webhook é registrado dentro de um projeto com POST /v1/projects/{project_id}/webhook-endpoints. Você escolhe a URL de destino e os tipos de evento aos quais ele se inscreve:
const response = await fetch(
`https://api.rollfuse.com/v1/projects/${projectId}/webhook-endpoints`,
{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/webhooks/rollfuse",
event_types: ["flag.published", "rollout.rolled_back"],
}),
},
);
const endpoint = await response.json();
console.log(endpoint.secret);
A resposta é o único momento em que secret é retornado em texto puro. Guarde-o agora, porque um GET posterior nos metadados do endpoint nunca traz esse valor de volta. Um projeto pode ter no máximo 20 endpoints de webhook, e um único endpoint pode se inscrever em no máximo 20 tipos de evento; passar de qualquer um dos dois limites volta como 400.
Tratando o payload recebido
Toda entrega é um corpo JSON com um formato de envelope: event_type, event_version, occurred_at e data. Aqui está um handler Express mínimo e completo que lê esse payload e reage a um evento flag.published:
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhooks/rollfuse", (req, res) => {
const { event_type, event_version, occurred_at, data } = req.body;
if (event_type === "flag.published") {
console.log(
`[${occurred_at}] flag ${data.feature_flag_id} no ambiente ${data.environment_id} agora está ${data.enabled ? "ativa" : "desativada"}`,
);
// invalide um cache local, atualize um dashboard, notifique um canal, etc.
}
if (event_type === "rollout.rolled_back") {
console.log(`[${occurred_at}] rollout sofreu rollback:`, data);
}
res.status(200).end();
});
app.listen(3000);
Responda com um status 2xx assim que aceitar o payload; qualquer trabalho mais lento em seguida (invalidar cache, mandar mensagem no Slack, disparar outro job) deve acontecer depois de já ter respondido, não antes. Este endpoint não documenta um esquema de assinatura para verificar que uma entrega veio mesmo do rollfuse, então trate o payload como trataria o de qualquer outro webhook de terceiro: valide os campos que você realmente usa e mantenha a rota difícil de adivinhar se precisar de uma camada extra de proteção.
Depurando uma entrega que falhou
Se o seu endpoint estava fora do ar ou retornou erro, o rollfuse guarda um registro de cada tentativa de entrega. Liste-as com GET /v1/webhook-endpoints/{webhook_endpoint_id}/deliveries:
const response = await fetch(
`https://api.rollfuse.com/v1/webhook-endpoints/${endpointId}/deliveries?limit=20`,
{ headers: { Authorization: `Bearer ${token}` } },
);
const deliveries = await response.json();
const falhas = deliveries.filter((d) => d.status !== "delivered");
console.log(falhas.map((d) => ({ id: d.id, motivo: d.last_failure_reason })));
A listagem traz só metadados, mais recente primeiro: status, attempt_count, last_attempted_at, next_attempt_at e last_failure_reason. Para ver o payload exato que foi enviado em uma entrega específica, busque-a individualmente:
const response = await fetch(
`https://api.rollfuse.com/v1/webhook-endpoints/${endpointId}/deliveries/${deliveryId}`,
{ headers: { Authorization: `Bearer ${token}` } },
);
const delivery = await response.json();
console.log(delivery.payload);
Essa resposta de entrega única inclui o payload completo, com envelope, que foi assinado e enviado, então dá para reproduzi-lo localmente contra o seu handler e confirmar a correção antes de esperar pelo próximo evento real.
Desativando um endpoint
Se precisar parar as entregas sem perder o histórico, desative o endpoint em vez de apagar qualquer coisa:
await fetch(
`https://api.rollfuse.com/v1/webhook-endpoints/${endpointId}/disable`,
{ method: "POST", headers: { Authorization: `Bearer ${token}` } },
);
Desativar é uma transição de ciclo de vida, não uma exclusão: o endpoint e todas as entregas já registradas nele continuam intactas, e nenhuma entrega nova é criada para ele daqui pra frente.
Com um webhook reagindo a mudanças de flag, o próximo passo natural é sincronizar dados externos de métrica com o rollfuse do mesmo jeito: veja Sincronize métricas externas com o rollfuse usando conectores.