Galet
Utiliser

Webhooks

Recevoir sur votre serveur les feedbacks créés, les changements de statut et les livraisons, signés par Galet.

Où : Paramètres → Webhooks. Réservé aux Admins.

Galet envoie un POST JSON à l'adresse de votre choix à chaque événement. Une organisation peut avoir 5 webhooks, chacun abonné aux événements qu'il veut. L'adresse doit être en https et publique.

Les événements

ÉvénementQuand
feedback.createdUn nouveau feedback est créé, quel que soit le canal
feedback.status_changedLe statut d'un feedback change, depuis l'inbox, l'API, le MCP ou le ticket Jira ou Linear lié
feedback.shippedUn feedback passe à delivered : le correctif est livré (envoyé en plus de feedback.status_changed)

Le corps

{
  "id": "evt_5c1f…",
  "type": "feedback.status_changed",
  "createdAt": "2026-10-13T21:40:12.000Z",
  "data": {
    "feedback": {
      "key": "FIF-12",
      "id": "tkt_…",
      "title": "Export CSV vide",
      "kind": "problem",
      "severity": "P1",
      "status": "fixed",
      "app": { "id": "app_…", "name": "Acme" },
      "reports": 3,
      "createdAt": "2026-10-10T08:02:11.000Z",
      "lastActivityAt": "2026-10-12T16:45:03.000Z",
      "url": "https://app.galet.dev/feedbacks/FIF-12"
    },
    "previousStatus": "in_development"
  }
}

data.feedback a la forme de GET /v1/feedbacks (voir la référence de l'API), lu au moment de l'envoi. previousStatus n'existe que pour les changements de statut. id identifie l'événement : il est le même pour chaque nouvelle tentative, servez-vous-en pour ignorer un doublon.

Vérifier la signature

Le secret (whsec_…) est affiché une seule fois, à la création du webhook. Chaque envoi porte l'en-tête :

Galet-Signature: t=1791934812,v1=5257a869e7ec…

v1 est le HMAC-SHA256, en hexadécimal, de <t>.<corps brut> avec le secret. Calculez-le sur le corps reçu tel quel, avant tout parsing, et refusez un t trop ancien (5 minutes, par exemple) pour bloquer le rejeu.

import { createHmac, timingSafeEqual } from "node:crypto"

function verify(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((part) => part.split("=")))
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false
  const expected = createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex")
  return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
}

Les en-têtes Galet-Event (le type) et Galet-Delivery (l'identifiant de l'envoi) accompagnent aussi chaque requête.

Réponse et nouvelles tentatives

Répondez 2xx en moins de 10 secondes ; faites le travail long après avoir répondu. Galet ne suit pas les redirections. Sans 2xx, Galet réessaie après 1 min, 5 min, 30 min, 2 h, 6 h, 12 h et 24 h, puis abandonne. Paramètres → Webhooks montre le résultat du dernier envoi de chaque webhook.

L'ordre d'arrivée n'est pas garanti : comparez createdAt si l'ordre compte.

On this page