API Webhook
Ceci est la référence technique du récepteur de webhook entrant de PrimeCal — le point de
terminaison qu'un système externe appelle pour déclencher une règle d'automatisation
webhook.incoming. Pour une présentation côté produit, voir
Webhooks dans le Guide utilisateur.
Chaque appel à ce point de terminaison est vérifié avec une signature HMAC-SHA256. Il n'y a
aucun moyen de désactiver cela par règle, et une requête non signée est catégoriquement
rejetée. Prévoyez la signature dès le départ ; un simple POST curl -d '{...}' échouera.
Point de terminaison
POST https://api.primecal.eu/api/automation/webhook/{token}
GET https://api.primecal.eu/api/automation/webhook/{token}
{token} est unique par règle (webhookToken), disponible dans l'onglet Webhook de la règle
dans l'application, et régénérable depuis là.
- POST — envoyez votre charge utile sous forme de corps JSON (
Content-Type: application/json). - GET — pour les appelants qui ne peuvent pas envoyer de corps POST (boutons IoT, liens déclenchés par navigateur). Les paramètres de chaîne de requête deviennent alors la charge utile.
Les deux variantes nécessitent la même signature.
Obtenir votre secret de signature
Chaque règle possède un webhookSecret, généré automatiquement à la création de la règle.
L'application web ne l'affiche pas actuellement — le seul moyen de le récupérer ou de le
faire tourner est ce point de terminaison :
POST /api/automation/rules/{id}/webhook/rotate-secret
Authentifié en tant que propriétaire de la règle (authentification JWT normale, pas le jeton webhook). Réponse :
{ "webhookSecret": "<nouveau secret hex de 128 caractères>", "graceUntil": "2026-09-26T12:00:00.000Z" }
Appeler ceci fait tourner le secret — l'ancien secret continue de fonctionner jusqu'à
graceUntil (1 heure par défaut), puis s'arrête. Il n'existe pas d'appel en lecture seule
« afficher le secret actuel » ; si vous avez perdu le secret, la rotation est le seul moyen de
récupération.
Signer une requête
- Horodatage — l'heure Unix actuelle en secondes, sous forme de chaîne.
- Charge utile signée —
"{timestamp}.{rawRequestBody}"(les octets exacts que vous envoyez, pas une version reséréialisée — pour les requêtes GET, utilisez une chaîne vide à la place du corps). - Signature —
HMAC-SHA256(webhookSecret, chargeUtileSignée), encodée en hexadécimal.
Envoyez les deux en en-têtes :
| En-tête | Valeur |
|---|---|
X-PrimeCal-Timestamp | L'horodatage Unix (secondes) utilisé ci-dessus |
X-PrimeCal-Signature | La signature hexadécimale, préfixée facultativement par sha256= |
(X-Webhook-Signature/X-Webhook-Timestamp et X-Hub-Signature-256 sont également acceptés,
pour la compatibilité avec les conventions courantes d'émetteurs de webhooks.)
Exemple (Node.js)
const crypto = require('crypto');
const secret = 'the webhookSecret from rotate-secret';
const body = JSON.stringify({ event: 'order.completed', data: { order_id: '12345' } });
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex');
await fetch('https://api.primecal.eu/api/automation/webhook/YOUR_TOKEN', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-PrimeCal-Timestamp': timestamp,
'X-PrimeCal-Signature': signature,
},
body,
});
Exemple (curl, précalculé)
SECRET="the webhookSecret from rotate-secret"
BODY='{"event":"order.completed","data":{"order_id":"12345"}}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')
curl -X POST "https://api.primecal.eu/api/automation/webhook/YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "X-PrimeCal-Timestamp: $TS" \
-H "X-PrimeCal-Signature: $SIG" \
-d "$BODY"
Tolérance d'horodatage et protection contre le rejeu
- L'horodatage doit être à moins de 5 minutes de l'horloge du serveur
(
WEBHOOK_TIMESTAMP_TOLERANCE_SECONDS, 300 par défaut). En dehors de cette fenêtre, la requête est rejetée — cela signifie aussi que vous ne pouvez pas rejouer une ancienne requête interceptée après la fermeture de la fenêtre. - Chaque combinaison
(token, signature, timestamp)ne peut être utilisée qu'une seule fois. Une nouvelle tentative identique octet pour octet de la même requête signée est rejetée comme rejeu.
Faire tourner sans interruption
rotate-secret donne à vos nouvelles requêtes un nouveau secret tandis que l'ancien
continue d'être vérifié jusqu'à graceUntil (1 heure par défaut). Mettez à jour le secret
stocké dans votre système externe dans cette fenêtre ; il n'y a aucun moyen de la prolonger
après coup — faites tourner à nouveau si vous avez besoin de plus de temps.
Limites de débit
Les appels webhook sont limités en débit par règle : 60 requêtes par fenêtre de 60 secondes
par défaut (AUTOMATION_WEBHOOK_MAX_PER_WINDOW / AUTOMATION_WEBHOOK_WINDOW_MS),
indépendamment des limites de débit générales de l'API décrites dans
Limites de débit de l'API. Le dépassement renvoie une erreur indiquant
le délai de nouvelle tentative.
Optionnel : restreindre par IP source
Une règle peut être configurée avec une liste blanche d'IP (triggerConfig) afin que seules
les requêtes provenant d'IP source spécifiques soient acceptées, en plus de la vérification de
signature. Cela se configure via l'API Automatisation, non exposé
actuellement dans l'interface du constructeur de règles.
Réponses
| Statut | Signification |
|---|---|
| 200 | { "success": true, "ruleId": <id>, "message": "Webhook processed successfully" } |
| 400 | Format de signature malformé, ou la règle n'est pas une règle webhook.incoming, ou la règle est désactivée |
| 401 | Signature manquante/invalide, horodatage hors tolérance, ou requête rejouée |
| 403 | La règle n'a aucun webhookSecret (ne devrait pas se produire pour une règle créée normalement) |
| 404 | Le jeton ne correspond à aucune règle |
| 429 | Limite de débit dépassée |
Un 200 signifie que la requête a été acceptée et évaluée — pas que les conditions de la règle correspondaient. Consultez le journal d'audit de la règle (API Automatisation) pour voir si l'action s'est réellement exécutée.
Sujets connexes
- Webhooks (Guide utilisateur) — forme de la charge utile, conditions, exemples pratiques
- API Automatisation — CRUD des règles, journaux d'audit, régénération de jeton
- Limites de débit de l'API