Webhooks
Les webhooks sont en cours de conception — non exposés en production. Cette page décrit le modèle prévu pour permettre aux intégrateurs de préparer leurs systèmes.
Vision
Permettre aux recruteurs et intégrateurs tiers (ATS, CRM, Slack, Discord) de recevoir des événements en push sans polling.
Événements prévus
| Événement | Déclencheur | Scope |
|---|
offre.published | Offre passe à PUBLISHED | Recruteur |
offre.closed | Offre fermée | Recruteur |
candidature.created | Nouveau candidat sur une offre | Recruteur |
candidature.status_changed | Transition pipeline | Recruteur |
candidat.hired | Candidature → HIRED | Recruteur |
recruiter.approved | Admin valide un recruteur | Admin |
recruiter.suspended | Sanction appliquée | Admin |
alert.triggered | Nouveau match d’alerte | Candidat (email seulement en v1) |
blog.comment.flagged | Commentaire signalé > 3 fois | Admin |
Modèle de payload
{
"id": "evt_01HX3R...",
"type": "candidature.created",
"createdAt": "2026-04-18T10:00:00Z",
"data": {
"candidatureId": 142,
"offreId": 55,
"candidatId": 17,
"statut": "NEW"
},
"deliveryAttempt": 1
}
Headers HTTP envoyés :
POST /your-webhook HTTP/1.1
Content-Type: application/json
X-Hive-Event: candidature.created
X-Hive-Delivery: dlv_01HX3R...
X-Hive-Signature: t=1713441600,v1=a1b2c3...
User-Agent: HiveWebhooks/1.0
Signature HMAC
Vérification (Node.js)
import crypto from 'crypto';
function verifyHiveSignature(rawBody, header, secret) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const expected = crypto
.createHmac('sha256', secret)
.update(`${parts.t}.${rawBody}`)
.digest('hex');
const valid = crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(parts.v1),
);
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) < 300;
return valid && fresh;
}
Vérification (Python)
import hmac, hashlib, time
def verify(raw_body: bytes, header: str, secret: str) -> bool:
parts = dict(p.split("=") for p in header.split(","))
expected = hmac.new(secret.encode(),
f"{parts['t']}.{raw_body.decode()}".encode(),
hashlib.sha256).hexdigest()
fresh = abs(time.time() - int(parts["t"])) < 300
return hmac.compare_digest(expected, parts["v1"]) and fresh
Politique de retry
| Tentative | Délai |
|---|
| 1 | immédiat |
| 2 | 30 s |
| 3 | 2 min |
| 4 | 10 min |
| 5 | 30 min |
| 6 | 1 h |
| 7 | 4 h |
| 8 | 12 h |
| 9 | 24 h |
| 10 | 48 h |
Timeout par tentative : 10 secondes.
Endpoints prévus
POST /v1/api/webhooks/subscriptions
GET /v1/api/webhooks/subscriptions
GET /v1/api/webhooks/subscriptions/{id}
PATCH /v1/api/webhooks/subscriptions/{id}
DELETE /v1/api/webhooks/subscriptions/{id}
GET /v1/api/webhooks/deliveries?subscriptionId=123
POST /v1/api/webhooks/deliveries/{id}/replay
GET /v1/api/webhooks/events # liste des types disponibles
Exemple de souscription
POST /v1/api/webhooks/subscriptions
{
"url": "https://ats.example.com/hive-webhook",
"events": ["candidature.created", "candidature.status_changed"],
"active": true,
"description": "ATS intégration Tech Corp"
}
Réponse avec secret à stocker :
{
"id": 12,
"url": "https://ats.example.com/hive-webhook",
"events": [...],
"secret": "whsec_abc123...",
"active": true
}
Alternative actuelle : polling
En attendant les webhooks, utiliser :
Fréquence recommandée : 60 secondes minimum (rate limit oblige).
Roadmap
Voir aussi