Menu de la documentation

Webhooks

Mooteck expose un point de réception pour recevoir vos événements (nouvelle réservation, mise à jour de stock) depuis votre boutique ou vos outils. Chaque requête doit être signée.

Sens des webhooks

Mooteck reçoit des webhooks ; il n'en émet pas vers votre boutique. La propagation Mooteck → boutique (catalogue, stock, commandes) se fait par des appels REST des connecteurs, pas par des webhooks sortants.

Endpoint

POST/api/web-integrations/webhook?key={uuid}

L'URL exacte (avec sa key) et le secret de webhooksont générés à la création de l'intégration dans Mooteck (Web → Connecter un site). Lakey identifie l'intégration ; le secret sert à la signature.

Signature

  • En-tête : x-mooteck-signature.
  • Algorithme : HMAC-SHA256, encodage hexadécimal.
  • Corps signé : le corps brut de la requête (octets exacts, avant tout parsing).
  • Format accepté : hex nu, ou préfixé sha256=<hex>.
  • Secret : le webhookSecret de votre intégration.
Vérifier / signer (Node.js)
import crypto from "crypto";

// Côté émetteur : signer le corps AVANT l'envoi
const raw = JSON.stringify(payload);            // le corps EXACT que vous enverrez
const signature = crypto
  .createHmac("sha256", WEBHOOK_SECRET)
  .update(raw, "utf8")
  .digest("hex");

await fetch(webhookUrl, {                        // webhookUrl contient déjà ?key=...
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-mooteck-signature": "sha256=" + signature,
  },
  body: raw,
});

Comparez en temps constant

Mooteck vérifie la signature avec une comparaison à temps constant. De votre côté, si vous recevez un jour des webhooks, faites de même (crypto.timingSafeEqual) et gardez le secret hors du code client.

Pas d'anti-rejeu horodaté

Le point de réception ne vérifie pas d'horodatage : une requête correctement signée est acceptée quel que soit son âge. Traitez vos événements de façon idempotente(déduplication par identifiant métier) pour éviter les doublons en cas de renvoi.

Événements

Le corps est { "event": "...", "data": { ... } }.

appointment_created

Requiert syncAppointments. Crée un rendez-vous.

Exemple
{
  "event": "appointment_created",
  "data": {
    "date": "2026-07-20T14:30:00+02:00",
    "type": "SERVICE",
    "clientName": "Jean Dupont",
    "clientPhone": "+32470000000",
    "notes": "Vidange"
  }
}

stock_update

Requiert syncStock. Met à jour la quantité d'un produit par référence (entier ≥ 0).

Exemple
{
  "event": "stock_update",
  "data": { "reference": "FIL-001", "quantity": 12 }
}
Réponse 200
{ "success": true }

Erreurs : 401 (key/signature/secret manquants ou invalides),400 (JSON, date ou quantité invalide).