Webhooks
Systeme de notification push. Enregistrez des webhooks pour recevoir des callbacks HTTP quand des evenements se produisent.
Types d'evenements
| Evenement | Description |
|---|---|
dossier.etat_changed | Un dossier change d'etat (ex: TRANSMIS vers ENGAGE) |
dossier.updated | Contenu d'un dossier modifie |
facture.etat_changed | Une facture change d'etat |
job.completed | Un job asynchrone termine avec succes |
job.failed | Un job asynchrone echoue |
job.progress | Progression d'un job (etape composite) |
sync.started | Un bulk sync demarre |
sync.batch | Un batch de sync est termine |
sync.completed | Un bulk sync termine |
Format du payload
Chaque notification est un POST JSON :
{
"event": "dossier.etat_changed",
"opcoId": "opco-ep",
"timestamp": "2024-06-01T10:00:00.000Z",
"data": { ... }
}Headers de la notification
| Header | Description |
|---|---|
Content-Type | application/json |
Opcovia-Signature | Signature HMAC-SHA256 du body (voir verification) |
Opcovia-Event | Type d'evenement (ex: dossier.etat_changed) |
Verification de la signature HMAC
Chaque webhook est associe a un secret (retourne a la creation). Opcovia signe le body avec HMAC-SHA256.
const crypto = require('crypto')
function verifySignature(body, secret, signature) {
const expected = crypto.createHmac('sha256', secret).update(body).digest('hex')
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}
// Dans votre handler HTTP :
const body = req.rawBody // string brut du body
const signature = req.headers['opcovia-signature']
if (!verifySignature(body, WEBHOOK_SECRET, signature)) {
return res.status(401).send('Invalid signature')
}Flux de verification de signature
Retries
En cas d'echec (non-2xx ou timeout), Opcovia retente 3 fois avec backoff :
- Tentative 1 : immediate
- Tentative 2 : apres 1 seconde
- Tentative 3 : apres 5 secondes
- Tentative 4 : apres 15 secondes
Timeout par tentative : 10 secondes.
POST /webhooks
Enregistrer un nouveau webhook.
Auth : X-API-KEY obligatoire.
Body (JSON)
{
"callbackUrl": "https://mon-app.com/webhooks/opcovia",
"events": ["dossier.etat_changed", "job.completed"],
"description": "Notifications dossiers"
}| Champ | Type | Requis | Description |
|---|---|---|---|
callbackUrl | string | Oui | URL HTTPS du callback (pas de localhost, pas de reseaux prives) |
events | array | Oui | Au moins 1 type d'evenement |
description | string | Non | Description libre |
Reponse 201
{
"id": "wh_abc123",
"callbackUrl": "https://mon-app.com/webhooks/opcovia",
"events": ["dossier.etat_changed", "job.completed"],
"secret": "a1b2c3d4e5f6...64chars...hex",
"active": true,
"description": "Notifications dossiers",
"createdAt": "2024-06-01T10:00:00.000Z"
}Important : Le secret n'est retourne qu'a la creation. Conservez-le.
GET /webhooks
Lister les webhooks du tenant.
Auth : X-API-KEY obligatoire.
Reponse 200
[
{
"id": "wh_abc123",
"callbackUrl": "https://mon-app.com/webhooks/opcovia",
"events": ["dossier.etat_changed", "job.completed"],
"active": true,
"description": "Notifications dossiers",
"createdAt": "2024-06-01T10:00:00.000Z"
}
]PATCH /webhooks/:id
Modifier un webhook existant. Seuls les champs fournis sont mis a jour.
Auth : X-API-KEY obligatoire.
Body (JSON, tous les champs optionnels)
{
"callbackUrl": "https://nouveau-url.com/webhook",
"events": ["dossier.etat_changed"],
"active": false,
"description": "Nouveau libelle"
}Reponse 200
{
"id": "wh_abc123",
"callbackUrl": "https://nouveau-url.com/webhook",
"events": ["dossier.etat_changed"],
"active": false,
"description": "Nouveau libelle"
}DELETE /webhooks/:id
Supprimer un webhook.
Auth : X-API-KEY obligatoire.
Reponse 200
{ "deleted": true }GET /webhooks/:id/logs
Historique des tentatives de livraison d'un webhook.
Auth : X-API-KEY obligatoire.
Reponse 200
[
{
"id": "del_xyz789",
"webhookId": "wh_abc123",
"event": "dossier.etat_changed",
"payload": { "event": "dossier.etat_changed", "opcoId": "opco-ep", ... },
"status": "delivered",
"statusCode": 200,
"attempts": 1,
"error": null,
"deliveredAt": "2024-06-01T10:00:01.000Z"
}
]Statuts de livraison : delivered, retrying, failed.