Skip to content

Webhooks (gestion des souscriptions)

Endpoints pour gérer vos souscriptions webhook depuis l'API publique. Pour comprendre comment recevoir et vérifier les webhooks émis, voir ../../webhooks/public-api-webhooks.md.

Source : server/publicApi/routes/webhooks.ts. Scope requis : webhooks:manage sur tous les endpoints.

Vue d'ensemble

MéthodePathDescription
GET/webhooksListe paginée des souscriptions
GET/webhooks/:idDétail d'une souscription
POST/webhooksCrée une souscription (renvoie le signingSecret une seule fois)
PATCH/webhooks/:idMet à jour (URL, events, headers, isActive)
DELETE/webhooks/:idSupprime
POST/webhooks/:id/testEnvoie un test.ping pour valider le endpoint
GET/webhooks/:id/deliveriesHistorique des livraisons (50 dernières par défaut, max 200)
GET/webhooks-eventsCatalogue complet des events disponibles

Catalogue d'événements

Liste complète exposée par GET /webhooks-events :

client.created, client.updated, client.deleted
contact.created, contact.updated, contact.deleted
website.created, website.updated, website.deleted
ticket.created, ticket.updated, ticket.deleted, ticket.status_changed
invoice.created, invoice.updated, invoice.paid, invoice.sent
quote.created, quote.updated, quote.accepted
task.created, task.updated, task.completed, task.deleted
event.created, event.updated, event.deleted
test.ping

Source : server/publicApi/webhookEmitter.ts:50-59.


POST /webhooks — créer une souscription

Body

ChampTypeRequisBornes
namestring1-100 chars
descriptionstring | null≤ 500 chars
urlstring (URL HTTPS)URL valide
eventsstring[]≥ 1 événement valide
maxRetriesint0-20 (défaut 5)
timeoutMsint1 000-60 000 (défaut 10 000)
headersrecord<string,string>Headers HTTP à ajouter aux requêtes
json
{
  "name": "Sync ma CRM maison",
  "description": "Reçoit les events client.* et invoice.paid",
  "url": "https://my-crm.example.com/stormeo/webhook",
  "events": ["client.created", "client.updated", "invoice.paid"],
  "maxRetries": 5,
  "timeoutMs": 10000,
  "headers": { "X-My-Custom-Header": "value" }
}

Réponse 201

json
{
  "id": 42,
  "name": "Sync ma CRM maison",
  "url": "https://my-crm.example.com/stormeo/webhook",
  "events": ["client.created", "client.updated", "invoice.paid"],
  "isActive": true,
  "maxRetries": 5,
  "timeoutMs": 10000,
  "createdAt": "2026-04-27T10:00:00.000Z",
  "signingSecret": "whsec_<64 hex>",
  "warning": "Copiez ce secret immédiatement. Il sera utilisé pour vérifier les signatures HMAC-SHA256."
}

⚠️ signingSecret n'est renvoyé qu'à la création. Stockez-le dans un secret manager. En cas de perte, supprimez la souscription et créez-en une nouvelle.


GET /webhooks / GET /webhooks/:id

Lecture. Le signingSecret n'est jamais retourné par ces endpoints (sécurité).

json
{
  "id": 42,
  "agencyId": 7,
  "name": "Sync ma CRM maison",
  "url": "https://my-crm.example.com/stormeo/webhook",
  "events": [...],
  "isActive": true,
  "lastDeliveryAt": "2026-04-27T10:05:00.000Z",
  "lastDeliveryStatus": "success",
  "failureCount": 0,
  "maxRetries": 5,
  "timeoutMs": 10000,
  "headers": {},
  "createdAt": "2026-04-27T10:00:00.000Z",
  "updatedAt": "2026-04-27T10:05:00.000Z"
}

PATCH /webhooks/:id

Mise à jour partielle. Champs autorisés : name, description, url, events, maxRetries, timeoutMs, headers, isActive.

Si vous repassez isActive: true après une désactivation, le failureCount est remis à 0.

Le signingSecret ne peut pas être modifié via PATCH. Pour rotation, supprimez et recréez.


DELETE /webhooks/:id

Suppression définitive de la souscription. Les webhook_deliveries historiques sont conservées (selon politique de rétention DB).


POST /webhooks/:id/test

Insère immédiatement un test.ping dans la queue. Le dispatcher (polling 10s) le pickera dans <15s.

Payload reçu sur votre URL

json
{
  "event": "test.ping",
  "data": {
    "message": "Test ping from StormeoOS",
    "timestamp": "2026-04-27T10:00:00.000Z",
    "subscriptionId": 42
  },
  "deliveryId": 12345,
  "timestamp": "2026-04-27T10:00:00.000Z"
}

Avec headers signature HMAC — voir ../../webhooks/public-api-webhooks.md.

Réponse 200

json
{ "ok": true, "message": "Ping enregistré, sera envoyé dans <15s" }

GET /webhooks/:id/deliveries

Historique des livraisons (succès + échecs). Triées par createdAt DESC.

Query params

ParamTypeDescription
limitintDéfaut 50, max 200

Réponse 200

json
[
  {
    "id": 12345,
    "subscriptionId": 42,
    "event": "client.created",
    "status": "success",
    "attempts": 1,
    "responseStatus": 200,
    "responseBody": "OK",
    "createdAt": "2026-04-27T10:05:00.000Z",
    "deliveredAt": "2026-04-27T10:05:01.000Z"
  },
  {
    "id": 12344,
    "subscriptionId": 42,
    "event": "invoice.paid",
    "status": "failed",
    "attempts": 5,
    "responseStatus": 503,
    "lastError": "timeout",
    "createdAt": "2026-04-27T09:30:00.000Z"
  }
]

Réponse en array brut, pas dans {data, total, ...} (incohérence à corriger en v2).

Statuts de livraison

statusDescription
pendingEn attente du prochain tick dispatcher
successReçu (HTTP 2xx)
failedÉchec après tous les retries
retryingEn cours de retry

Bonnes pratiques

  • Endpoint receiver idempotent : utilisez le deliveryId pour dédupliquer côté serveur. StormeoOS peut envoyer le même event 2x en cas de timeout réseau côté retry.
  • Répondez rapidement (<10s par défaut) avec un 2xx. Reportez le traitement lourd dans une queue interne.
  • Vérifiez la signature HMAC systématiquement avant de traiter. Voir ../../webhooks/public-api-webhooks.md.
  • Whitelist d'IPs : les webhooks sortants partent toutes du serveur StormeoOS prod (193.108.54.10). Vous pouvez restreindre votre endpoint à cette IP en plus de la signature.

StormeoOS API